无法在“对象”实例上设置属性班级

发布于 2024-08-07 09:33:59 字数 602 浏览 2 评论 0 原文

所以,我在回答这个问题时正在玩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 语言规范中的哪些内容规定不能将属性分配给普通对象?


有关其他解决方法,请参阅如何创建对象并向其添加属性?

So, I was playing around with Python while answering this question, and I discovered that this is not valid:

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:

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?


For other workarounds, see How can I create an object and add attributes to it?.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

旧时浪漫 2024-08-14 09:33:59

为了支持任意属性分配,对象需要一个__dict__:与该对象关联的字典,可以在其中存储任意属性。否则,就没有地方可以放置新属性。

object 的实例携带 __dict__ ——如果携带的话,在可怕的循环依赖问题之前(因为 dict< /code> 与大多数其他内容一样,继承自 object;-),这将为 Python 中的每个 对象配备一个字典,这意味着 的开销当前没有或不需要字典的每个对象有许多字节(本质上,所有没有任意可分配属性的对象都没有或不需要字典)。

例如,使用优秀的 pympler 项目(您可以通过 svn 从 这里),我们可以做一些测量...:

>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16

您不会希望每个 int 占用 144 个字节而不是仅 16 个字节,对吗?-)

现在,当您创建一个类(从任何继承),事情发生了变化...:

>>> class dint(int): pass
... 
>>> asizeof.asizeof(dint(23))
184

...现在添加了 __dict__ (另外,还有一点额外的开销) - 所以 < code>dint 实例可以具有任意属性,但您为此灵活性付出了相当大的空间成本。

那么,如果您想要 int 只带有一个 额外属性 foobar...?这是一种罕见的需求,但 Python 确实为此目的提供了一种特殊的机制...

>>> class fint(int):
...   __slots__ = 'foobar',
...   def __init__(self, x): self.foobar=x+100
... 
>>> asizeof.asizeof(fint(23))
80

...不像 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 (since dict, like most everything else, inherits from object;-), 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...:

>>> 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?-)

Now, when you make a class (inheriting from whatever), things change...:

>>> class dint(int): pass
... 
>>> asizeof.asizeof(dint(23))
184

...the __dict__ is now added (plus, a little more overhead) -- so a dint instance can have arbitrary attributes, but you pay quite a space cost for that flexibility.

So what if you wanted ints with just one extra attribute foobar...? It's a rare need, but Python does offer a special mechanism for the purpose...

>>> class fint(int):
...   __slots__ = 'foobar',
...   def __init__(self, x): self.foobar=x+100
... 
>>> asizeof.asizeof(fint(23))
80

...not quite as tiny as an int, mind you! (or even the two ints, one the self and one the self.foobar -- the second one can be reassigned), but surely much better than 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 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).

海的爱人是光 2024-08-14 09:33:59

正如其他回答者所说,对象没有__dict__object所有类型的基类,包括intstr。因此,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, 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.


Instead of doing an instance of a dummy class, in Python 3.3+, you can (and should) use types.SimpleNamespace for this.

£噩梦荏苒 2024-08-14 09:33:59

这仅仅是由于优化。

字典相对较大。

>>> import sys
>>> sys.getsizeof((lambda:1).__dict__)
140

在 C 中定义的大多数(也许是全部)类没有用于优化的字典。

如果您查看源代码< /a> 你会看到有很多检查来查看对象是否有字典。

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.

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.

陪我终i 2024-08-14 09:33:59

因此,在调查我自己的问题时,我发现了关于 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'

我假设最后的错误是因为 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:

>>> 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".

君勿笑 2024-08-14 09:33:59

https://docs.python.org/3/library/functions.html#对象

注意对象 是否没有__dict__,因此您不能将任意属性分配给 对象类。


https://docs.python.org/3/library/functions.html#object :

Note: object does not have a __dict__, so you can’t assign arbitrary attributes to an instance of the object class.

独﹏钓一江月 2024-08-14 09:33:59

这是因为对象是一种“类型”,而不是一个类。一般来说,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.

我是男神闪亮亮 2024-08-14 09:33:59

这是(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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文