无法在“对象"的实例上设置属性班级 [英] Can't set attributes on instance of "object" class

查看:19
本文介绍了无法在“对象"的实例上设置属性班级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我在回答的同时玩弄Python这个问题,我发现这是无效的:

o = object()o.attr = '你好'

由于 AttributeError: 'object' 对象没有属性 'attr'.但是,对于任何继承自 object 的类,它都是有效的:

class Sub(object):经过s = 子()s.attr = '你好'

打印 s.attr 按预期显示hello".为什么会这样?Python 语言规范中有什么规定不能为 vanilla 对象分配属性?

解决方案

为了支持任意属性分配,对象需要一个 __dict__:一个与对象关联的字典,可以存储任意属性.否则,就无处可放置新属性.

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

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

<预><代码>>>>从 pympler 导入 asizeof>>>asizeof.asizeof({})144>>>asizeof.asizeof(23)16

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

现在,当你创建一个类(从任何东西继承)时,事情就会改变......:

<预><代码>>>>类 dint(int):通过...>>>asizeof.asizeof(dint(23))184

...__dict__ 现在添加(加上,更多的开销)——所以 dint 实例可以具有任意属性,但您为这种灵活性付出了相当大的空间成本.

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

<预><代码>>>>类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 语句(更准确地说,默认元类,typecode>) 并不是为该类的每个实例配备一个 __dict__(因此具有任意属性的能力),只是一组有限的、刚性的槽"(基本上每个地方都可以保存对某个对象的一个​​引用)具有给定的名称.

作为失去灵活性的交换,您为每个实例获得了大量字节(可能只有当您有无数个实例四处游荡时才有意义,但是, 有这样的用例).>

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?

解决方案

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

这篇关于无法在“对象"的实例上设置属性班级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆