所以,我在回答 this question 的时候正在玩弄 Python ,我发现这是无效的:
o = object()
o.attr = 'hello'
由于 AttributeError: 'object' object has no attribute 'attr'
。但是,对于从 object 继承的任何类,它都是有效的:
class Sub(object):
pass
s = Sub()
s.attr = 'hello'
打印 s.attr
会按预期显示“hello”。为什么会这样? Python 语言规范中的哪些内容指定您不能将属性分配给原始对象?
有关其他解决方法,请参阅 How can I create an object and add attributes to it? .
最佳答案
为了支持任意属性赋值,一个对象需要一个__dict__
:一个与对象关联的dict,可以存储任意属性。否则,没有地方可以放置新属性。
object
的一个实例不携带一个__dict__
——如果它携带,在可怕的循环依赖问题之前(因为dict
,像大多数其他东西一样,继承自 object
;-),这将使 Python 中的每个对象都带有一个 dict,这意味着开销许多 每个对象当前没有或不需要字典的字节(本质上,所有不具有任意可分配属性的对象都没有或不需要字典)。
例如,使用优秀的 pympler
项目(您可以通过 svn 从 here 获取它),我们可以进行一些测量...:
>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16
您不会希望每个 int
占用 144 个字节而不是 16 个字节,对吗?-)
现在,当您创建一个类(继承自任何类)时,情况会发生变化...:
>>> class dint(int): pass
...
>>> asizeof.asizeof(dint(23))
184
...现在添加了 __dict__
(另外,还有一点开销)——因此 dint
实例可以具有任意属性,但您为此灵 active 付出了相当大的空间成本。
那么,如果您想要 int
仅具有 一个 额外属性 foobar
... 怎么办?这是一个罕见的需求,但 Python 确实为此目的提供了一种特殊的机制......
>>> class fint(int):
... __slots__ = 'foobar',
... def __init__(self, x): self.foobar=x+100
...
>>> asizeof.asizeof(fint(23))
80
...不是相当int
那么小,请注意! (甚至是两个 int
,一个是 self
,一个是 self.foobar
—— 第二个可以重新分配),但肯定比 dint
好得多。
当类具有__slots__
特殊属性(字符串序列)时,则class
声明(更准确地说,默认元类,type
) 不为该类的每个实例配备 __dict__
(因此具有任意属性的能力),只是一组有限的、严格的“插槽”(基本上每个地方都可以保存一个对某个对象的引用)具有给定的名称。
作为失去灵 active 的交换,每个实例会获得大量字节(可能只有当您有无数个实例在闲逛时才有意义,但是有用例)。 p>
关于python - 无法在 "object"类的实例上设置属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22846089/