在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'
同样,可以将属性添加到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'
为什么我不能将成员添加到list
的实例中?是不是因为list
是内置类型?
更一般地说,Python中的哪些对象可以动态添加属性?
答案 0 :(得分:1)
在对象上设置任意属性时,这会有效地改变对象的__dict__
。 __dict__
是存储对象的所有成员的字典。因此,为了向对象添加成员,有两个条件:
__dict__
。__dict__
需要是可变的。有多种原因可能导致其中一种情况不正确。以下类别的类型通常不允许对象修改:
int
,str
,list
,bytes
,...可能是大多数(但不是全部)built-in types __slots__
的任何Python类。插槽是转换__dict__
的明确方式,而是由一组固定的成员替换它。很明显,这将阻止以后添加到对象(按设计)。检测是否可以修改对象有什么好方法?好吧,检查上面的条件。对象是否具有__dict__
:
>>> class Example:
pass
>>> class SlotsExample:
__slots__ = ['x']
>>> hasattr(Example(), '__dict__')
True
>>> hasattr(SlotsExample(), '__dict__')
False
>>> hasattr(list, '__dict__')
True
>>> hasattr([], '__dict__')
False
__dict__
是否是真正的字典:
>>> isinstance(Example().__dict__, dict)
True
>>> isinstance(list.__dict__, dict)
False
答案 1 :(得分:0)
简而言之,它取决于__setattr__
魔法。
通过__getattr__
和__setattr__
检索Python属性。如果您有没有它们的类,则应用默认值。 (插槽有点不同。)
对于内置/扩展类型(CPython中的HEAPTYPE
),默认情况下您无法添加任何其他属性,但是您可以通过提供其他功能来覆盖它。 (纯Python不可能。)