无法设置对象类的属性

所以,当我回答这个问题时,我正在玩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的基类,包括intstr 。 因此,无论由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中实现的类不能在运行时修改的事实…子类可以,但不是基类。