所以,我在回答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语言规范中的内容指定您不能将属性分配给vanilla对象?
6 回答
这只是因为优化 .
Dicts相对较大 .
在C中定义的大多数(可能是所有)类都没有用于优化的字典 .
如果你看source code,你会看到有很多检查,看看对象是否有一个字典 .
为了支持任意属性赋值,对象需要
__dict__
:与对象关联的dict,其中可以存储任意属性 . 否则,无处可放新属性 .object
的一个实例 not 携带__dict__
- 如果确实如此,那么在可怕的循环依赖问题之前(因为dict
,就像大多数其他一切一样,继承自object
;-),这会使Python中的每个对象都带有一个dict,将意味着每个对象的许多字节的开销,目前没有任意可分配的属性没有或不需要dict) .例如,使用优秀的
pympler
项目(您可以通过here的svn获取它),我们可以做一些测量...:你不希望每个
int
占用144个字节而不是16个,对吧? - )现在,当你创建一个类(继承自任何东西)时,事情会改变......:
...现在添加了
__dict__
(加上一点开销) - 所以dint
实例可以有任意属性,但是你为这种灵活性付出了相当大的空间成本 .那么,如果你只想要一个额外的属性_178230_,那该怎么办?这是一种罕见的需求,但Python确实为此提供了一种特殊的机制......
......不像_1782303那么小,请注意! (甚至两个
int
,一个self
和一个self.foobar
- 第二个可以重新分配),但肯定比dint
好多了 .当类具有
__slots__
特殊属性(字符串序列)时,class
语句(更确切地说,默认元类,type
)确实 not 为该类的每个实例配备__dict__
(因此具有任意属性的能力) ,只是一个有限的,刚性的"slots"(基本上每个都可以保存对某个对象的一个引用的地方)和给定的名称 .为了弥补灵活性的损失,你可以获得每个实例的大量字节(仅当你有数以万计的实例加入时才有意义,但是,有一些用例) .
正如其他回答者所说,
object
没有__dict__
.object
是 all 类型的基类,包括int
或str
. 因此,_1782320提供的任何内容也将成为他们的负担 . 即使像可选的__dict__
这样简单的东西也需要为每个值添加额外的指针;这会为系统中的每个对象浪费额外的4-8个字节的内存,这对于非常有限的实用程序 .在Python 3.3中,您可以(并且应该)使用types.SimpleNamespace而不是虚拟类的实例 .
因此,在调查我自己的问题时,我发现了有关Python语言的内容:你可以继承像int这样的东西,你会看到相同的行为:
我假设最后的错误是因为add函数返回一个int,所以我必须覆盖像
__add__
之类的函数,以便保留我的自定义属性 . 但是这一切现在对我来说都是有道理的(我想),当我想起"object"时"int" .这是因为对象是“类型”,而不是类 . 通常,在C扩展中定义的所有类(如所有内置数据类型和numpy数组之类的东西)都不允许添加任意属性 .
这是(IMO)Python的基本限制之一 - 您无法重新打开类 . 我认为实际的问题是由于在C中实现的类不能在运行时修改的事实...子类可以,但不是基类 .