Sma*_*ery 81 python attributes language-design
所以,我在回答这个问题时正在玩Python ,我发现这是无效的:
o = object()
o.attr = 'hello'
Run Code Online (Sandbox Code Playgroud)
由于AttributeError: 'object' object has no attribute 'attr'.但是,对于从object继承的任何类,它是有效的:
class Sub(object):
pass
s = Sub()
s.attr = 'hello'
Run Code Online (Sandbox Code Playgroud)
打印s.attr按预期显示"你好".为什么会这样?Python语言规范中的内容指定您不能将属性分配给vanilla对象?
Ale*_*lli 122
为了支持任意属性赋值,对象需要__dict__:与对象关联的字典,其中可以存储任意属性.否则,无处可放新属性.
的实例object并没有随身携带__dict__-如果它这样做了,可怕的循环依赖问题(因为之前dict,像其他所有的事情,从继承object;-),这将鞍每一个在Python对象有一个字典,这将意味着开销当前没有或不需要dict的每个对象的许多字节(实质上,所有没有任意可分配属性的对象都没有或不需要dict).
例如,使用优秀的pympler项目(你可以从这里通过svn获得它),我们可以做一些测量...:
>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16
Run Code Online (Sandbox Code Playgroud)
你不希望每个int人占用144个字节而不是16个,对吧? - )
现在,当你创建一个类(继承自任何东西)时,事情会改变......:
>>> class dint(int): pass
...
>>> asizeof.asizeof(dint(23))
184
Run Code Online (Sandbox Code Playgroud)
...的__dict__ 是现在又增加了(加,多一点开销) -所以一个dint实例可以有任意的属性,但是你付出相当的灵活性的空间成本.
所以,如果你想ints的只是一个额外的属性foobar...?这是一种罕见的需求,但Python确实为此提供了一种特殊的机制......
>>> class fint(int):
... __slots__ = 'foobar',
... def __init__(self, x): self.foobar=x+100
...
>>> asizeof.asizeof(fint(23))
80
Run Code Online (Sandbox Code Playgroud)
......不要那么小int,请注意!(甚至两个ints,一个self和一个self.foobar- 第二个可以重新分配),但肯定比a好多了dint.
当类具有__slots__特殊属性(字符串序列),那么class语句(更准确地说,默认元类type)并没有装备有该类的每个实例__dict__(有任意属性,因此的能力),只是一个有限,具有给定名称的刚性"槽"集(基本上每个可以对一些对象保持一个引用的位置).
为了弥补灵活性的损失,你可以获得每个实例的大量字节(仅当你有数以万计的实例加入时才有意义,但是,有一些用例).
Ant*_*ala 17
正如其他回答者所说,一个object没有__dict__.object是所有类型的基类,包括int或str.因此,提供的任何东西也object将成为他们的负担.即使像可选的 那样简单,__dict__也需要为每个值添加额外的指针; 这会为系统中的每个对象浪费额外的4-8个字节的内存,这对于非常有限的实用程序.
在Python 3.3+中,您可以(而且应该)使用它types.SimpleNamespace来代替虚拟类的实例.
| 归档时间: |
|
| 查看次数: |
12944 次 |
| 最近记录: |