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

时间:2017-10-03 01:16:15

标签: python oop object dynamic attributes

在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中的哪些对象可以动态添加属性?

2 个答案:

答案 0 :(得分:1)

在对象上设置任意属性时,这会有效地改变对象的__dict____dict__是存储对象的所有成员的字典。因此,为了向对象添加成员,有两个条件:

  1. 对象需要__dict__
  2. 对象的__dict__需要是可变的。
  3. 有多种原因可能导致其中一种情况不正确。以下类别的类型通常不允许对象修改:

    • 内置的 native 类型在本机代码中实现,并具有一组固定的成员,并附加到其本机对象定义中。示例包括intstrlistbytes,...可能是大多数(但不是全部)built-in types
    • 来自外部库的
    • Native 类型,例如numpy stuff。
    • 使用__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不可能。)