Trước hết, gần như luôn là một ý tưởng tồi để làm một việc như vậy. Nếu chỉ có lý do tại sao bạn muốn đó là đảm bảo rằng bạn không làm lỗi chính tả - có những công cụ tốt hơn cho điều đó (nghĩ IDE hoặc pylint). Nếu bạn là 100% tích cực mà bạn cần một điều như vậy, dưới đây là hai cách để làm điều đó:
Cách đầu tiên - bạn có thể làm điều này bằng cách sử dụng phương pháp __setattr__
. Xem python __setattr__
documentation
class Person(object):
def __init__(self, first_name, last_name):
self.__dict__['first_name'] = first_name
self.__dict__['last_name'] = last_name
def __setattr__(self, name, value):
if name in self.__dict__:
super(Person, self).__setattr__(name, value)
else:
raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name))
và đầu ra:
In [49]: a = Person(1, 2)
In [50]: a.a = 2
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 a.a = 2
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in __setattr__(self, name, value)
8 super(Person, self).__setattr__(name, value)
9 else:
---> 10 raise AttributeError("%s has no attribute %s" %(self.__class__.__name__, name))
AttributeError: Person has no attribute a
Ngoài ra, bạn có thể làm điều này bằng __slots__
(python __slots__
documentation):
class Person(object):
__slots__ = ("first_name", "last_name")
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
đầu ra:
In [32]: a = Person("a", "b")
In [33]: a.first_name
Out[33]: 'a'
In [34]: a.a = 1
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/usr/local/lib/python2.7/dist-packages/django/core/management/commands/shell.pyc in <module>()
----> 1 a.a = 1
AttributeError: 'Person' object has no attribute 'a'
Cách thứ nhất linh hoạt hơn vì nó cho phép hack mã này hơn nữa bằng cách sử dụng trực tiếp __dict__
, nhưng điều đó thậm chí còn sai lệch hơn bây giờ. Cách tiếp cận thứ hai preallocates không gian cho số lượng nhất định các biến dụ (tham khảo), có nghĩa là tiêu thụ bộ nhớ ít hơn.
Tôi nghĩ đây là một ví dụ về những gì mọi người gọi là "vá khỉ", và tôi nghĩ đó là một trong những điều mọi người yêu thích về Python. Nghe có vẻ như bạn đang chiến đấu với ngôn ngữ. – BenDundee
Nếu bạn thực sự phải, '__slots__' có thể đạt được những gì bạn đang tìm kiếm để làm. Tuy nhiên, nó thực sự không nên được sử dụng cho điều này ... Tôi sẽ xem xét rằng '__slots__' lạm dụng. Cuối cùng, đây là lý do tại sao bạn cần cung cấp một API nhất quán và tài liệu tốt. Nếu người dùng gặp lỗi, họ sẽ tìm ra rằng họ không sử dụng đúng API của bạn. – mgilson
@BenDundee: monkeypatching chủ yếu là thêm/sửa đổi hành vi khi chạy. Trong khi dựa vào các cơ chế tương tự, ví dụ trên chắc chắn là một lỗi đánh máy, không phải là một con khỉ;) –