无法在“对象”实例上设置属性班级
所以,我在回答这个问题时正在玩Python< /a>,我发现这是无效的:
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 语言规范中的哪些内容规定不能将属性分配给普通对象?
有关其他解决方法,请参阅如何创建对象并向其添加属性?。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
为了支持任意属性分配,对象需要一个
__dict__
:与该对象关联的字典,可以在其中存储任意属性。否则,就没有地方可以放置新属性。object
的实例不携带__dict__
——如果携带的话,在可怕的循环依赖问题之前(因为dict< /code> 与大多数其他内容一样,继承自
object
;-),这将为 Python 中的每个 对象配备一个字典,这意味着 的开销当前没有或不需要字典的每个对象有许多字节(本质上,所有没有任意可分配属性的对象都没有或不需要字典)。例如,使用优秀的
pympler
项目(您可以通过 svn 从 这里),我们可以做一些测量...:您不会希望每个
int
占用 144 个字节而不是仅 16 个字节,对吗?-)现在,当您创建一个类(从任何继承),事情发生了变化...:
...现在添加了
__dict__
(另外,还有一点额外的开销) - 所以 < code>dint 实例可以具有任意属性,但您为此灵活性付出了相当大的空间成本。那么,如果您想要
int
只带有一个 额外属性foobar
...?这是一种罕见的需求,但 Python 确实为此目的提供了一种特殊的机制......不像
int
那么小,请注意! (或者甚至是两个int
,一个是self
,一个是self.foobar
——第二个可以重新分配),但肯定的是比dint
好得多。当类具有 __slots__ 特殊属性(字符串序列)时,则使用
class
语句(更准确地说,是默认元类,type
)是否不为该类的每个实例配备一个__dict__
(因此能够具有任意属性),只是一组有限的、严格的“槽”(基本上是放置每个对象都可以保存对某个对象的引用)以及给定的名称。作为失去灵活性的代价,每个实例都会获得大量字节(只有当您有无数实例在运行时才可能有意义,但是,有这样的用例)。
To support arbitrary attribute assignment, an object needs a
__dict__
: a dict associated with the object, where arbitrary attributes can be stored. Otherwise, there's nowhere to put new attributes.An instance of
object
does not carry around a__dict__
-- if it did, before the horrible circular dependence problem (sincedict
, like most everything else, inherits fromobject
;-), this would saddle every object in Python with a dict, which would mean an overhead of many bytes per object that currently doesn't have or need a dict (essentially, all objects that don't have arbitrarily assignable attributes don't have or need a dict).For example, using the excellent
pympler
project (you can get it via svn from here), we can do some measurements...:You wouldn't want every
int
to take up 144 bytes instead of just 16, right?-)Now, when you make a class (inheriting from whatever), things change...:
...the
__dict__
is now added (plus, a little more overhead) -- so adint
instance can have arbitrary attributes, but you pay quite a space cost for that flexibility.So what if you wanted
int
s with just one extra attributefoobar
...? It's a rare need, but Python does offer a special mechanism for the purpose......not quite as tiny as an
int
, mind you! (or even the twoint
s, one theself
and one theself.foobar
-- the second one can be reassigned), but surely much better than adint
.When the class has the
__slots__
special attribute (a sequence of strings), then theclass
statement (more precisely, the default metaclass,type
) does not equip every instance of that class with a__dict__
(and therefore the ability to have arbitrary attributes), just a finite, rigid set of "slots" (basically places which can each hold one reference to some object) with the given names.In exchange for the lost flexibility, you gain a lot of bytes per instance (probably meaningful only if you have zillions of instances gallivanting around, but, there are use cases for that).
正如其他回答者所说,
对象
没有__dict__
。object
是所有类型的基类,包括int
或str
。因此,object
提供的任何东西都将成为他们的负担。即使像可选这样简单的__dict__
也需要为每个值提供一个额外的指针;对于非常有限的实用程序来说,这会为系统中的每个对象浪费额外的 4-8 字节内存。在 Python 3.3+ 中,您可以(并且应该)使用 ,而不是执行虚拟类的实例
types.SimpleNamespace
为此。As other answerers have said, an
object
does not have a__dict__
.object
is the base class of all types, includingint
orstr
. Thus whatever is provided byobject
will be a burden to them as well. Even something as simple as an optional__dict__
would need an extra pointer for each value; this would waste additional 4-8 bytes of memory for each object in the system, for a very limited utility.Instead of doing an instance of a dummy class, in Python 3.3+, you can (and should) use
types.SimpleNamespace
for this.这仅仅是由于优化。
字典相对较大。
在 C 中定义的大多数(也许是全部)类没有用于优化的字典。
如果您查看源代码< /a> 你会看到有很多检查来查看对象是否有字典。
It is simply due to optimization.
Dicts are relatively large.
Most (maybe all) classes that are defined in C do not have a dict for optimization.
If you look at the source code you will see that there are many checks to see if the object has a dict or not.
因此,在调查我自己的问题时,我发现了关于 Python 语言的这一点:您可以从 int 之类的东西继承,并且您会看到相同的行为:
我假设最后的错误是因为 add 函数返回一个 int,所以我必须重写诸如 __add__ 之类的函数才能保留我的自定义属性。但是,当我想到像“int”这样的“对象”时,这一切现在对我来说都是有意义的(我认为)。
So, investigating my own question, I discovered this about the Python language: you can inherit from things like int, and you see the same behaviour:
I assume the error at the end is because the add function returns an int, so I'd have to override functions like
__add__
and such in order to retain my custom attributes. But this all now makes sense to me (I think), when I think of "object" like "int".https://docs.python.org/3/library/functions.html#对象:
https://docs.python.org/3/library/functions.html#object :
这是因为对象是一种“类型”,而不是一个类。一般来说,C 扩展中定义的所有类(如所有内置数据类型和 numpy 数组之类的东西)都不允许添加任意属性。
It's because object is a "type", not a class. In general, all classes that are defined in C extensions (like all the built in datatypes, and stuff like numpy arrays) do not allow addition of arbitrary attributes.
这是(IMO)Python 的基本限制之一 - 你不能重新打开类。不过,我相信实际的问题是由以下事实引起的:用 C 实现的类无法在运行时修改……子类可以,但基类不行。
This is (IMO) one of the fundamental limitations with Python - you can't re-open classes. I believe the actual problem, though, is caused by the fact that classes implemented in C can't be modified at runtime... subclasses can, but not the base classes.