python 无法设置对象类的属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1529002/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can't set attributes of object class
提问by Smashery
So, I was playing around with Python while answering this question, and I discovered that this is not valid:
所以,我在回答这个问题时正在玩 Python ,我发现这是无效的:
o = object()
o.attr = 'hello'
due to an AttributeError: 'object' object has no attribute 'attr'
. However, with any class inherited from object, it is valid:
由于AttributeError: 'object' object has no attribute 'attr'
. 但是,对于从 object 继承的任何类,它都是有效的:
class Sub(object):
pass
s = Sub()
s.attr = 'hello'
Printing s.attr
displays 'hello' as expected. Why is this the case? What in the Python language specification specifies that you can't assign attributes to vanilla objects?
打印s.attr
按预期显示“你好”。为什么会这样?Python 语言规范中的哪些内容指定不能为 vanilla 对象分配属性?
回答by Alex Martelli
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 putnew attributes.
为了支持任意属性分配,对象需要一个__dict__
: 与对象关联的字典,其中可以存储任意属性。否则,没有地方可以放置新属性。
An instance of object
does notcarry around a __dict__
-- if it did, before the horrible circular dependence problem (since dict
, like most everything else, inherits from object
;-), this would saddle everyobject in Python with a dict, which would mean an overhead of manybytes 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).
的实例object
并没有随身携带__dict__
-如果它这样做了,可怕的循环依赖问题(之前因为dict
,像其他所有的事情,从继承object
;-),这将鞍每一个在Python对象有一个字典,这将意味着开销每个对象的许多字节当前没有或不需要字典(本质上,所有没有任意分配属性的对象都没有或需要字典)。
For example, using the excellent pympler
project (you can get it via svn from here), we can do some measurements...:
例如,使用优秀的pympler
项目(你可以从这里通过 svn 获得它),我们可以做一些测量......:
>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16
You wouldn't want every int
to take up 144 bytes instead of just 16, right?-)
您不会希望每个都int
占用 144 个字节而不是 16 个字节,对吗?-)
Now, when you make a class (inheriting from whatever), things change...:
现在,当你创建一个类(从任何东西继承)时,事情就会改变......:
>>> class dint(int): pass
...
>>> asizeof.asizeof(dint(23))
184
...the __dict__
isnow added (plus, a little more overhead) -- so a dint
instance can have arbitrary attributes, but you pay quite a space cost for that flexibility.
...的__dict__
是现在又增加了(加,多一点开销) -所以一个dint
实例可以有任意的属性,但是你付出相当的灵活性的空间成本。
So what if you wanted int
s with just oneextra attribute foobar
...? It's a rare need, but Python does offer a special mechanism for the purpose...
那么如果你想要int
s 只需要一个额外的属性foobar
呢......?这是一种罕见的需求,但 Python 确实为此提供了一种特殊的机制......
>>> class fint(int):
... __slots__ = 'foobar',
... def __init__(self, x): self.foobar=x+100
...
>>> asizeof.asizeof(fint(23))
80
...not quiteas tiny as an int
, mind you! (or even the two int
s, one the self
and one the self.foobar
-- the second one can be reassigned), but surely much better than a dint
.
...没有那么小int
,请注意!(甚至两个int
s,一个 theself
和一个 the self.foobar
- 第二个可以重新分配),但肯定比 a 好得多dint
。
When the class has the __slots__
special attribute (a sequence of strings), then the class
statement (more precisely, the default metaclass, type
) does notequip 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.
当类具有__slots__
特殊属性(字符串序列),那么class
语句(更准确地说,默认元类type
)并没有装备该类的每个实例有一个__dict__
(有任意属性,因此的能力),只是一个有限,具有给定名称的一组刚性“插槽”(基本上是每个位置都可以保存对某个对象的一个引用)。
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 areuse cases for that).
作为失去灵活性的交换,您会为每个实例获得大量字节(可能只有当您有无数个实例四处游荡时才有意义,但是,有一些用例)。
回答by Antti Haapala
As other answerers have said, an object
does not have a __dict__
. object
is the base class of alltypes, including int
or str
. Thus whatever is provided by object
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.
正如其他回答者所说, anobject
没有__dict__
. object
是所有类型的基类,包括int
or str
。因此,无论提供什么,object
对他们来说也是一种负担。即使是像可选项__dict__
这样简单的东西,每个值也需要一个额外的指针;对于非常有限的实用程序,这会为系统中的每个对象浪费额外的 4-8 字节内存。
Instead of doing an instance of a dummy class, in Python 3.3+, you can (and should) use types.SimpleNamespace
for this.
在 Python 3.3+ 中,您可以(并且应该)使用它types.SimpleNamespace
,而不是做一个虚拟类的实例。
回答by Unknown
It is simply due to optimization.
这只是由于优化。
Dicts are relatively large.
字典比较大。
>>> import sys
>>> sys.getsizeof((lambda:1).__dict__)
140
Most (maybe all) classes that are defined in C do not have a dict for optimization.
在 C 中定义的大多数(也许所有)类都没有用于优化的字典。
If you look at the source codeyou will see that there are many checks to see if the object has a dict or not.
如果您查看源代码,您会发现有很多检查可以查看对象是否具有 dict。
回答by Smashery
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:
因此,在调查我自己的问题时,我发现了有关 Python 语言的这一点:您可以从 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'
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".
我认为最后的错误是因为 add 函数返回一个 int,所以我必须覆盖诸如此类的函数__add__
以保留我的自定义属性。但这一切现在对我来说都有意义(我认为),当我想到像“int”这样的“对象”时。
回答by Ryan
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.
这是因为对象是一个“类型”,而不是一个类。通常,在 C 扩展中定义的所有类(如所有内置数据类型,以及 numpy 数组之类的东西)都不允许添加任意属性。
回答by Peter
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.
这是 (IMO) Python 的基本限制之一 - 您无法重新打开类。不过,我相信实际的问题是由于无法在运行时修改在 C 中实现的类的事实造成的……子类可以,但基类不能。