无法设置对象类的属性
所以,当我回答这个问题时,我正在玩Python,而且我发现这是无效的:
o = object() o.attr = 'hello'
由于AttributeError: 'object' object has no attribute 'attr'
。 但是,对于从对象inheritance的任何类,它是有效的:
class Sub(object): pass s = Sub() s.attr = 'hello'
按预期打印s.attr
显示“hello”。 这是为什么? Python语言规范中的哪些内容指定您不能将属性分配给vanilla对象?
为了支持任意的属性赋值,一个对象需要一个__dict__
:一个与对象关联的字典,其中可以存储任意的属性。 否则,没有什么地方可以提供新的属性。
object
一个实例并不包含__dict__
,如果是这样的话,在可怕的循环依赖问题之前(因为dict
和大多数其他东西一样,inheritance自object
;-),所以这会使Python中的每个对象都有一个dict,将意味着每个对象的许多字节的开销,目前没有或需要一个字典(实质上,没有任意可分配属性的所有对象没有或需要字典)。
例如,使用优秀的pympler
项目(你可以通过svn从这里获得 ),我们可以做一些测量…:
>>> from pympler import asizeof >>> asizeof.asizeof({}) 144 >>> asizeof.asizeof(23) 16
你不希望每个int
都占用144个字节而不是16个,对吧?)
现在,当你创build一个类(inheritance任何东西)时,事物会改变…:
>>> class dint(int): pass ... >>> asizeof.asizeof(dint(23)) 184
…现在添加了__dict__
(加上一点点的开销),所以一个dint
实例可以有任意的属性,但是你为这种灵活性付出了相当大的空间成本。
那么如果你想要int
只有一个额外的属性foobar
…? 这是一个罕见的需求,但Python确实提供了一个特殊的机制…
>>> class fint(int): ... __slots__ = 'foobar', ... def __init__(self, x): self.foobar=x+100 ... >>> asizeof.asizeof(fint(23)) 80
… …不像一个int
小,请记住你! (或者甚至是两个整体,一个是self
,一个是self
self.foobar
– 第二个可以重新分配),但肯定比力度要好得多。
当类具有__slots__
特殊属性(一系列string)时,那么class
语句(更确切地说是默认的元type
)不会为该类的每个实例都配备__dict__
(因此可以具有任意属性) ,只是一个有限的,固定的“槽”(基本上可以容纳一个对象的引用的地方)与给定的名称。
为了弥补灵活性的损失,每个实例可以获得大量的字节数(只有当您有大量的实例在其周围闲逛时才有意义,但是有一些用例)。
正如其他答复者所说,一个object
没有__dict__
。 object
是所有types的基类,包括int
或str
。 因此,无论由object
提供什么也将成为他们的负担。 即使像可选的 __dict__
这样简单的东西也需要一个额外的指针, 这将为系统中的每个对象浪费额外的4-8字节的内存,这是非常有限的效用。
而不是在Python 3.3+中做一个虚拟类的实例,你可以(也应该)为此使用types.SimpleNamespace
。
这只是由于优化。
口授是比较大的。
>>> import sys >>> sys.getsizeof((lambda:1).__dict__) 140
在C中定义的大多数(也许是全部)类没有优化的词典。
如果你看源代码,你会看到有很多检查,看看对象是否有字典。
这是因为对象是一个“types”,而不是一个类。 通常,在C扩展中定义的所有类(如所有内置的数据types,以及类似numpy数组的东西)都不允许添加任意属性。
所以,调查一下我自己的问题,我发现了Python语言的这个问题:你可以inheritance像int这样的东西,你会看到相同的行为:
>>> class MyInt(int): pass >>> x = MyInt() >>> print x 0 >>> x.hello = 4 >>> print x.hello 4 >>> x = x + 1 >>> print x 1 >>> print x.hello Traceback (most recent call last): File "<interactive input>", line 1, in <module> AttributeError: 'int' object has no attribute 'hello'
我假设在最后的错误是因为add函数返回一个int,所以我不得不覆盖__add__
等这样的函数,以保留我的自定义属性。 但是,当我想到像“int”这样的“object”的时候,这一切对我来说都是有意义的(我认为)。
这是(IMO)Python的基本限制之一 – 你不能重新打开类。 我相信,实际问题,是由于在C中实现的类不能在运行时修改的事实…子类可以,但不是基类。