为什么无法在Python中给对象添加属性?

70 投票
2 回答
35807 浏览
提问于 2025-04-15 13:38

(在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__,这就是为什么不能动态地给属性赋值。我重新整理了我的回答,让这个更清楚(把第二段移到最上面)。

撰写回答