2009-08-16 34 views
53

(viết bằng Python vỏ)Tại sao bạn không thể thêm thuộc tính vào đối tượng trong python?

>>> o = object() 
>>> o.test = 1 

Traceback (most recent call last): 
    File "<pyshell#45>", line 1, in <module> 
    o.test = 1 
AttributeError: 'object' object has no attribute 'test' 
>>> class test1: 
    pass 

>>> t = test1() 
>>> t.test 

Traceback (most recent call last): 
    File "<pyshell#50>", line 1, in <module> 
    t.test 
AttributeError: test1 instance has no attribute 'test' 
>>> t.test = 1 
>>> t.test 
1 
>>> class test2(object): 
    pass 

>>> t = test2() 
>>> t.test = 1 
>>> t.test 
1 
>>> 

Tại sao không phải đối tượng cho phép bạn thêm thuộc tính cho nó?

Trả lời

38

Chú ý rằng một thể hiện object không có __dict__ thuộc tính:

>>> dir(object()) 
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__'] 

Một ví dụ để minh họa cho hành vi này trong một lớp học có nguồn gốc:

>>> class Foo(object): 
...  __slots__ = {} 
... 
>>> f = Foo() 
>>> f.bar = 42 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'Foo' object has no attribute 'bar' 

Trích dẫn từ các tài liệu trên slots:

[...] Việc kê khai __slots__ mất s một chuỗi các biến cá thể và dự trữ chỉ đủ không gian trong mỗi cá thể để giữ một giá trị cho mỗi biến. Không gian được lưu vì __dict__ không được tạo cho từng trường hợp.

EDIT: Để trả lời ThomasH từ các nhận xét, lớp kiểm tra của OP là một lớp "kiểu cũ". Hãy thử:

>>> class test: pass 
... 
>>> getattr(test(), '__dict__') 
{} 
>>> getattr(object(), '__dict__') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'object' object has no attribute '__dict__' 

và bạn sẽ nhận thấy có trường hợp __dict__. Lớp đối tượng có thể không được định nghĩa là __slots__, nhưng kết quả giống nhau: thiếu một số __dict__, điều này ngăn cản việc gán động của một thuộc tính. Tôi đã tổ chức lại câu trả lời của mình để làm cho điều này rõ ràng hơn (di chuyển đoạn thứ hai lên trên).

+2

Vì vậy, bạn đang nói rằng lớp * đối tượng đang sử dụng \ _ \ _ slots \ _ \ _ theo cách này hay cách khác, để ngăn việc gán các thành viên cá thể. Đây có phải là một giả định hoặc một thực tế (tức là nó trong việc thực hiện * đối tượng *)? Bởi vì sự vắng mặt của \ _ \ dict \ _ \ _ từ một đối tượng * object * không phải là dấu hiệu. Các cá thể của lớp * test1 * của OP cho thấy cùng một thiếu \ _ \ _ dict \ _ \ _ khi được gọi với dir(), nhưng cho phép gán các thành viên instance. – ThomasH

+1

@ThomasH, vui lòng xem ghi chú tôi đã thêm vào câu trả lời. – ars

3

Câu hỏi hay, tôi đoán là nó phải làm với thực tế là object là một loại mở rộng/mở rộng /loại mở rộng.

>>> class test(object): 
... pass 
... 
>>> test.test = 1 
>>> object.test = 1 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: can't set attributes of built-in/extension type 'object' 

IIRC, điều này đã làm với sự hiện diện của một thuộc tính __dict__ hoặc, đúng hơn, setattr() thổi lên khi đối tượng không có một thuộc tính __dict__.

Các vấn đề liên quan