为什么无法在Python中给对象添加属性?
(在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
>>>
为什么对象不允许你给它添加属性呢?
2 个回答
5
好问题,我猜这和 object
是一种 内置/扩展类型 有关。
>>> 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'
如果我没记错的话,这和 __dict__
属性的存在有关,或者更准确地说,当对象没有 __dict__
属性时,使用 setattr()
会出错。
57
注意,一个 object
实例没有 __dict__
属性:
>>> dir(object())
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__']
下面是一个例子,来说明在派生类中这种行为:
>>> 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'
引用文档中关于 slots
的内容:
[...]
__slots__
声明了一系列实例变量,并为每个实例保留了足够的空间来存放每个变量的值。这样可以节省空间,因为每个实例不会创建__dict__
。
编辑:为了回答评论中的 ThomasH,OP 的测试类是一个“旧式”类。试试:
>>> 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__'
你会发现有一个 __dict__
实例。虽然对象类可能没有定义 __slots__
,但结果是一样的:缺少 __dict__
,这就是为什么不能动态地给属性赋值。我重新整理了我的回答,让这个更清楚(把第二段移到最上面)。