Python中的哪些对象可以动态添加属性?

use*_*783 5 python oop attributes dynamic object

在Python中,我可以向C先前定义的类添加属性。但是,我无法向其中添加属性list-产生的错误消息说明这是因为list是内置类型:

>>> class C: pass
...
>>> C.foo = 1
>>> C.foo
1

>>> list.foo = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'list'
Run Code Online (Sandbox Code Playgroud)

同样,可以将属性添加到的实例C,但不能添加到的实例list。但是,在这种情况下,错误消息更加模糊:

>>> o = C()
>>> o.bar = 2
>>> o.bar
2

>>> o = []
>>> o.bar = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'bar'
Run Code Online (Sandbox Code Playgroud)

为什么不能将成员添加到的实例list?还是因为list是内置类型?

更一般而言,Python中的哪些对象可以动态添加属性?

pok*_*oke 2

在对象上设置任意属性时,这会有效地改变 object\xe2\x80\x99s __dict__。这__dict__是一个存储对象所有成员的字典。所以要向对象添加成员,需要满足两个条件:

\n\n
    \n
  1. 该对象需要有一个__dict__.
  2. \n
  3. 对象\xe2\x80\x99s__dict__需要是可变的。
  4. \n
\n\n

有多种原因可能导致其中一个条件不成立。以下类别的类型通常不允许对象修改:

\n\n
    \n
  • 内置本机类型在本机代码中实现,并具有一组固定的成员,并融入其本机对象定义中。示例包括int, str, list, bytes, \xe2\x80\xa6 可能是大多数(但不是全部)内置类型
  • \n
  • 来自外部库的本机类型,例如 numpy 的东西。
  • \n
  • 任何使用__slots__. 槽位是一种明确的方式,可以__dict__用一组固定的成员来代替它。显然,这将阻止以后添加对象(根据设计)。
  • \n
\n\n

检测是否可以修改对象的好方法是什么?好吧,检查上面的条件。对象是否具有__dict__:

\n\n
>>> class Example:\n        pass\n>>> class SlotsExample:\n        __slots__ = [\'x\']\n\n>>> hasattr(Example(), \'__dict__\')\nTrue\n>>> hasattr(SlotsExample(), \'__dict__\')\nFalse\n>>> hasattr(list, \'__dict__\')\nTrue\n>>> hasattr([], \'__dict__\')\nFalse\n
Run Code Online (Sandbox Code Playgroud)\n\n

以及是否__dict__是真正的字典:

\n\n
>>> isinstance(Example().__dict__, dict)\nTrue\n>>> isinstance(list.__dict__, dict)\nFalse\n
Run Code Online (Sandbox Code Playgroud)\n