题
的目的是什么 __slots__
在蟒蛇,尤其是相对于当我想要使用它,时不?
解决方案
在Python的目的是什么
__slots__
和什么样的情况下,应该避免这种情况?
TLDR:
特别属性 __slots__
可以让你明确说明哪个实例属性的预期对象的情况下,与预期结果:
- 速度更快 属性访问。
- 节省空间 在存储器。
节省的空间是从
- 保存价值的参考文献在隙,而不是的
__dict__
. - 否认
__dict__
和__weakref__
创建,如果父类拒绝他们和你声明__slots__
.
快速警告
小小的警告,则应只宣布一个特定的老虎一个时间在继承树。例如:
class Base:
__slots__ = 'foo', 'bar'
class Right(Base):
__slots__ = 'baz',
class Wrong(Base):
__slots__ = 'foo', 'bar', 'baz' # redundant foo and bar
蟒蛇不对象当你得到这是错误的(它也许应该),问题可能不无清单,但你的对象将采取更多的空间,比他们否则应。
>>> from sys import getsizeof
>>> getsizeof(Right()), getsizeof(Wrong())
(64, 80)
最大的警告是多个继承-多"父母课程与非空隙"不能合并。
为适应这种限制,按照最佳做法:找出所有,但一个或所有父母的抽象,他们的具体类别和你的新的具体类统将继承给抽象(s)空隙(只是喜欢抽象的基类标准图书馆)。
看到部在多个继承下面的一个例子。
要求:
有属性命名
__slots__
实际上是存在,而不是一个插槽__dict__
, 一类必须继承object
.防止创建一个
__dict__
, 你必须继承object
和所有的类别,在继承必须声明__slots__
没有他们可以有一个'__dict__'
项。
有很多的信息,如果你要继续读。
为什么使用 __slots__
:快属性访问。
创作者的Python,Guido van Rossum, 国 他实际上创建的 __slots__
为更快的属性访问。
这是微不足道,表现出明显的重大更快地访问:
import timeit
class Foo(object): __slots__ = 'foo',
class Bar(object): pass
slotted = Foo()
not_slotted = Bar()
def get_set_delete_fn(obj):
def get_set_delete():
obj.foo = 'foo'
obj.foo
del obj.foo
return get_set_delete
和
>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085
槽的访问是几乎30%的速度在Python3.5在Ubuntu。
>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342
在蟒蛇2上窗户我已经测量的约15%的速度。
为什么使用 __slots__
:存储蓄
另一个目的 __slots__
是减少空间,在存储器,每一对象的实例需要。
空间保存在使用
__dict__
可能是重大的。
SQLAlchemy属性 很多记忆的储蓄来 __slots__
.
来验证这一点,使用蟒蛇的分布Python2.7在Ubuntu Linux, guppy.hpy
(aka heapy)和 sys.getsizeof
, ,大小的一个类实例,而不 __slots__
声明,没有别的,是64字节。这并 不 包括 __dict__
.谢谢你Python懒惰的评价再次, __dict__
显然不是所谓的入的存在,直到它被引用,但类没有数据通常都是无用的。当叫到存在, __dict__
属性是最低的280字此外。
与此相反,一个类实例 __slots__
宣布 ()
(无数据)只有16个字节,56总字节的一个项目的时隙,64有两个。
64位蟒蛇,我说明存储的消耗字节Python2.7和3.6, __slots__
和 __dict__
(没有插槽的定义)对每一个点,在那里dict增长3.6(除了为0、1、2个属性):
Python 2.7 Python 3.6
attrs __slots__ __dict__* __slots__ __dict__* | *(no slots defined)
none 16 56 + 272† 16 56 + 112† | †if __dict__ referenced
one 48 56 + 272 48 56 + 112
two 56 56 + 272 56 56 + 112
six 88 56 + 1040 88 56 + 152
11 128 56 + 1040 128 56 + 240
22 216 56 + 3344 216 56 + 408
43 384 56 + 3344 384 56 + 752
因此,尽管小字典Python3,我们怎么看很好 __slots__
规模的实例,以保存我们的记忆,这是一个主要原因,你就想要使用 __slots__
.
只是为了完整起见,我注意到,请注意,有一次性费用每槽类的名字空间的64字节蟒蛇2和72个字节Python3,因为槽的使用数据描述性质,所谓的"成员"。
>>> Foo.foo
<member 'foo' of 'Foo' objects>
>>> type(Foo.foo)
<class 'member_descriptor'>
>>> getsizeof(Foo.foo)
72
示范 __slots__
:
拒绝建立一个 __dict__
, 你必须亚类 object
:
class Base(object):
__slots__ = ()
现在:
>>> b = Base()
>>> b.a = 'a'
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
b.a = 'a'
AttributeError: 'Base' object has no attribute 'a'
或亚类的另一类定义 __slots__
class Child(Base):
__slots__ = ('a',)
和现在:
c = Child()
c.a = 'a'
但是:
>>> c.b = 'b'
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
c.b = 'b'
AttributeError: 'Child' object has no attribute 'b'
允许 __dict__
建立时继承槽的对象,只是增加 '__dict__'
来的 __slots__
(注意槽是命令,你不应该重复隙,已经在母体类):
class SlottedWithDict(Child):
__slots__ = ('__dict__', 'b')
swd = SlottedWithDict()
swd.a = 'a'
swd.b = 'b'
swd.c = 'c'
和
>>> swd.__dict__
{'c': 'c'}
或者你甚至都不需要宣布 __slots__
在你的子类,并且你仍然会使用的时隙从父母,但不限制建立一个 __dict__
:
class NoSlots(Child): pass
ns = NoSlots()
ns.a = 'a'
ns.b = 'b'
并且:
>>> ns.__dict__
{'b': 'b'}
但是, __slots__
可能引起问题的多个继承:
class BaseA(object):
__slots__ = ('a',)
class BaseB(object):
__slots__ = ('b',)
因为创建一个子类从父母与非空隙失败:
>>> class Child(BaseA, BaseB): __slots__ = ()
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
class Child(BaseA, BaseB): __slots__ = ()
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict
如果你遇到这个问题,你 可能 只是删除 __slots__
从父母,或者如果你有控制的父母,给他们空隙,或进行重构,以抽象:
from abc import ABC
class AbstractA(ABC):
__slots__ = ()
class BaseA(AbstractA):
__slots__ = ('a',)
class AbstractB(ABC):
__slots__ = ()
class BaseB(AbstractB):
__slots__ = ('b',)
class Child(AbstractA, AbstractB):
__slots__ = ('a', 'b')
c = Child() # no problem!
添加 '__dict__'
要 __slots__
获得动态的分配:
class Foo(object):
__slots__ = 'bar', 'baz', '__dict__'
和现在:
>>> foo = Foo()
>>> foo.boink = 'boink'
所以 '__dict__'
在槽我们失去了一些大小的利益与上具有动态的分配仍然具有插槽的名字我们的期望。
当你继承的对象不是槽,你会得到同样的语义的时候你使用 __slots__
-名字在 __slots__
点到槽的价值观,而其他任何价值观都放在实例 __dict__
.
避免 __slots__
因为你想要可以添加的属性是实际上不是一个很好的理由-只是添加 "__dict__"
你的 __slots__
如果这是必需的。
你可以添加类似地 __weakref__
要 __slots__
明确如果你需要的特征。
设置空元组,当一个子类namedtuple:
该namedtuple内作出不可改变的情况下,这是非常轻量级(从本质上讲,小组),但得到的好处,需要做你自己如果你的亚类:
from collections import namedtuple
class MyNT(namedtuple('MyNT', 'bar baz')):
"""MyNT is an immutable and lightweight object"""
__slots__ = ()
使用:
>>> nt = MyNT('bar', 'baz')
>>> nt.bar
'bar'
>>> nt.baz
'baz'
和试图分配一个意想不到的属性提出了一个 AttributeError
因为我们必须防止创建的 __dict__
:
>>> nt.quux = 'quux'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'MyNT' object has no attribute 'quux'
你的 可以 允许 __dict__
创造留下掉 __slots__ = ()
, 但你不能使用非空 __slots__
有的亚型的元组。
最大的警告:多个继承
即使在非空隙是一样多的父母,他们不能一起使用:
class Foo(object):
__slots__ = 'foo', 'bar'
class Bar(object):
__slots__ = 'foo', 'bar' # alas, would work if empty, i.e. ()
>>> class Baz(Foo, Bar): pass
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
multiple bases have instance lay-out conflict
使用空 __slots__
在父似乎提供最大的灵活性, 让孩子选择,以防止或允许 (通过加入 '__dict__'
获得动态的分配,见第段) 建立一个 __dict__
:
class Foo(object): __slots__ = ()
class Bar(object): __slots__ = ()
class Baz(Foo, Bar): __slots__ = ('foo', 'bar')
b = Baz()
b.foo, b.bar = 'foo', 'bar'
你不 已 有时隙-所以如果你加入他们,并删除后,它不应该造成任何问题。
出去肢体上在这里:如果你是在写 混入 或者使用 抽象的基类, ,它不是旨在可实例,一个空的 __slots__
在那些父母似乎是最好的方式方面的灵活性subclassers.
来证明,第一,让我们创建一个类代码我们就要使用多个继承
class AbstractBase:
__slots__ = ()
def __init__(self, a, b):
self.a = a
self.b = b
def __repr__(self):
return f'{type(self).__name__}({repr(self.a)}, {repr(self.b)})'
我们可以利用上述直接通过继承和声明的预期槽:
class Foo(AbstractBase):
__slots__ = 'a', 'b'
但我们不关心那,那是微不足道的单一的继承,我们需要另外一类,我们可能还会继承,也许有嘈杂的属性:
class AbstractBaseC:
__slots__ = ()
@property
def c(self):
print('getting c!')
return self._c
@c.setter
def c(self, arg):
print('setting c!')
self._c = arg
现在,如果这两个基地已经非空隙,我们不能这样做。(事实上,如果我们希望,我们可以给 AbstractBase
非空隙a和b、并给他们留下了以下的宣言》,使他们在将是错误的):
class Concretion(AbstractBase, AbstractBaseC):
__slots__ = 'a b _c'.split()
现在我们有功能都通过多个继承、并仍然可以拒绝 __dict__
和 __weakref__
实例:
>>> c = Concretion('a', 'b')
>>> c.c = c
setting c!
>>> c.c
getting c!
Concretion('a', 'b')
>>> c.d = 'd'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Concretion' object has no attribute 'd'
其他情况下,以避免插槽:
- 避免他们当你想要执行
__class__
分配与另一类不让他们(和你不能把它们添加)除非槽的布局完全相同。(我非常有兴趣学习的人是谁这样做,以及为什么。) - 避免他们如果您想要子类的变量的长度的内置喜欢长,tuple,或str,和你需要添加的属性。
- 避免他们,如果你坚持要求提供的默认值通过的类属性,例如变量。
你可以梳理出进一步说明从其他的 __slots__
文件(第3.7开发文件的最新), 我有了显着的最近的贡献。
批评其他的答案
目前的前的答案举过时的信息和相当手-波浪和错过标记的,在一些重要方面。
不要"仅仅使用 __slots__
当实例很多的对象"
我引述:
"你会想要使用
__slots__
如果你要的实例很多(数以百计,成千上万)为对象的同类。"
抽象的基础课程,例如,从 collections
模块,是不实例,但 __slots__
都宣布他们。
为什么?
如果一个用户的愿望要否认 __dict__
或 __weakref__
创作,这些事情必不可在父母的课程。
__slots__
有助于可重复使用性时,建立接口或混入.
这是事实,许多Python用户是不是写作的重用,但是当你是有选择拒绝不必要的空间使用情况是有价值的。
__slots__
不打破洗
当酸洗槽目的,你可能会发现其抱怨与一个误导 TypeError
:
>>> pickle.loads(pickle.dumps(f))
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
这实际上是不正确的。这消息是来自最早的协议,这是默认的。你可以选择最新的协议 -1
参数。在Python2.7这将是 2
(其中引入了2.3),并在3.6它 4
.
>>> pickle.loads(pickle.dumps(f, -1))
<__main__.Foo object at 0x1129C770>
在Python2.7:
>>> pickle.loads(pickle.dumps(f, 2))
<__main__.Foo object at 0x1129C770>
在Python3.6
>>> pickle.loads(pickle.dumps(f, 4))
<__main__.Foo object at 0x1129C770>
所以我会记住这一点,因为它是个解决问题。
批评的(直到Oct2,2016年)接受的答案
第一段是一半的简短说明,一半的预测。这里是唯一一部分,实际上答案的问题
正确使用
__slots__
为节省空间的物体。而不是具有动态字典,可以添加的属性为对象在任何时候,有一个静态结构,该结构不允许增加之后创建。这样可以节省开销的一个词典对每个对象使用的插槽
第二一半是一厢情愿的想法,和关闭的标记:
虽然这有时是一个有用的优化,这将是完全不必要的,如果Python解释是动态的,足以使它只会要求的字典时,有实际上是增加的对象。
蟒蛇实际上没有的东西与此类似,只有创造 __dict__
当它被访问,但是,创造很多物品没有数据是相当荒谬的。
第二段过分简化和错过了实际的原因,以避免 __slots__
.以下是 不 一个真正的原因,以避免隙(对 实际 原因,看看其他的,我的答案同上。):
他们改变行为的对象,有时隙在一种方式,可能会被滥用的控制狂静态和打字的维也纳香肠.
它然后接着讨论的其他方式实现这一不正当目标与Python,不讨论任何与 __slots__
.
第三段是更多的是一厢情愿的想法。在一起这是主要的标记内容的回答者甚至没有作者,并有助于弹药的批评者的网站。
存储器使用的证据
创造一些正常的对象和分的对象:
>>> class Foo(object): pass
>>> class Bar(object): __slots__ = ()
实例一百万的人:
>>> foos = [Foo() for f in xrange(1000000)]
>>> bars = [Bar() for b in xrange(1000000)]
检查与 guppy.hpy().heap()
:
>>> guppy.hpy().heap()
Partition of a set of 2028259 objects. Total size = 99763360 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 1000000 49 64000000 64 64000000 64 __main__.Foo
1 169 0 16281480 16 80281480 80 list
2 1000000 49 16000000 16 96281480 97 __main__.Bar
3 12284 1 987472 1 97268952 97 str
...
访问定期对象和他们的 __dict__
检查再次:
>>> for f in foos:
... f.__dict__
>>> guppy.hpy().heap()
Partition of a set of 3028258 objects. Total size = 379763480 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 1000000 33 280000000 74 280000000 74 dict of __main__.Foo
1 1000000 33 64000000 17 344000000 91 __main__.Foo
2 169 0 16281480 4 360281480 95 list
3 1000000 33 16000000 4 376281480 99 __main__.Bar
4 12284 0 987472 0 377268952 99 str
...
这是一致的历史,蟒蛇,从 统一的种类和类Python2.2
如果你的亚类的一个内置的类型,额外的空间将自动增加的情况,以适应
__dict__
和__weakrefs__
.(的__dict__
不是初始化,直到你用它,虽然,所以你不应该担心占用的空间由一个空洞的词典的每一个实例。) 如果你不需要这个额外的空间,可以添加的短语"__slots__ = []
"你的类。
其他提示
雅各哈伦:
在正确使用
__slots__
的是节省空间中的对象。相反,具有 动态字典,允许随时添加属性的对象, 有一个静态结构不允许创建后添加。 [此使用__slots__
消除了一个字典的开销为每个对象。虽然这有时是一个非常有用的优化,这将是完全 不必要的,如果Python解释器是动态的,足以使它会 仅要求的dict当有实际上是增加的对象。不幸的是,一个副作用时隙。他们改变行为 具有在某种程度上时隙中的对象,可以通过控制欲被滥用 和静态类型怪人。这是不好的,因为控制狂应 被滥用元类和静态类型怪人应该是滥用 装饰,因为在Python,应该做的事情只有一个明显的方式。
制作的CPython足够聪明地处理节省空间没有
的变化的列表上__slots__
是一个重大的 事业,这可能是为什么它不是P3K(还)。
您可能需要使用__slots__
如果你要实例化同一个类的对象很多(几百,几千)。 __slots__
只存在作为存储优化工具。
这是非常气馁使用__slots__
用于约束属性的创建,一般要避免它,因为它打破泡菜,与Python的一些其他功能的反省沿。
每个蟒对象具有__dict__
atttribute其是含有所有其它属性的字典。例如当你输入self.attr
蟒蛇其实就是做self.__dict__['attr']
。正如你可以想像使用字典来存储属性将用于访问它的一些额外的空间和时间。
然而,当使用__slots__
,该类创建的任何对象将不具有__dict__
属性。相反,所有属性访问是通过指针直接完成。
所以,如果想要一个C风格的结构,而不是你可以使用__slots__
用于压实物体的大小和减少属性存取时间完全成熟的类。一个很好的例子是包含属性X和Y一个点类。如果你想有一分不少,你可以尝试使用__slots__
为了节省一些内存。
在除了其他的答案,在这里是使用__slots__
的示例:
>>> class Test(object): #Must be new-style class!
... __slots__ = ['x', 'y']
...
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__',
'__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']
因此,为了实现__slots__
,只需要一个额外的行(,使您的类的新样式类,如果是没有的话)。这样,您就可以减少这些类5倍的内存占用时,在具有编写自定义泡菜的代码,如果并且当必要的费用。
槽用于库调用,以消除“命名方法分派”造函数调用时非常有用的。这是在痛饮文档提及。对于希望减少用于使用时隙通常被称为功能的功能的开销高性能库要快得多。
现在这可以不直接相关的有机磷问题。它更多地涉及建筑物的扩展比它使用在物体上的槽强>语法。但它确实有助于完成插槽的使用和一些推理他们身后的照片。
一个类的实例的属性有3个属性:该情况下,属性的名称和属性的值
在<强> 规则属性的访问 下,该实例用作字典和属性的名称作为在字典中的关键查找值。
<强>实例(属性) - >值强>
在<强> __ slots__中访问 下,该属性的名称充当字典和实例充当在字典中的关键查找值。
<强>属性(实例) - >值强>
在<强> 轻量级图案 下,该属性的名称充当字典和值作为该字典的关键查找所述实例。
<强>属性(值) - >实例强>
__slot__
属性的一个非常简单的例子。
问题:如果没有__slots__
如果我没有在我的课__slot__
属性,我可以添加新的属性,以我的对象。
class Test:
pass
obj1=Test()
obj2=Test()
print(obj1.__dict__) #--> {}
obj1.x=12
print(obj1.__dict__) # --> {'x': 12}
obj1.y=20
print(obj1.__dict__) # --> {'x': 12, 'y': 20}
obj2.x=99
print(obj2.__dict__) # --> {'x': 99}
如果你看一下上面的例子,你可以看到, OBJ1 和 OBJ 2 有自己的 X 和Ÿ属性和python还创建为每个对象dict
属性(的 OBJ1 和<强> OBJ2 强>)。
假设,如果我的类的测试有成千上万这样的对象?创建针对每个对象的附加属性dict
将导致大量的开销(存储器,计算能力等)在我的代码。
解决方案:通过__slots__
现在在下面的例子中我的类的测试强>包含__slots__
属性。现在,我不能将新属性添加到我的对象(除属性x
)和Python不会再创建一个dict
属性。这消除了开销为每个对象,如果你有很多的对象,可以成为显著。
class Test:
__slots__=("x")
obj1=Test()
obj2=Test()
obj1.x=12
print(obj1.x) # --> 12
obj2.x=99
print(obj2.x) # --> 99
obj1.y=28
print(obj1.y) # --> AttributeError: 'Test' object has no attribute 'y'
另一个有些模糊使用__slots__
的是将属性添加到从ProxyTypes包对象代理,原PEAK项目的一部分。它ObjectWrapper
允许您代理另一个对象,而是拦截与代理对象的所有交互。是不是很常用的(没有Python 3的支持),但我们用它来实现围绕基于龙卷风异步实现,弹跳通过ioloop所有访问代理对象的线程安全的阻塞包装,使用线程安全concurrent.Future
对象同步和返回结果。
默认情况下,以代理对象的任何属性的访问会给你从代理对象的结果。如果需要代理对象上添加一个属性,__slots__
都可以使用。
from peak.util.proxies import ObjectWrapper
class Original(object):
def __init__(self):
self.name = 'The Original'
class ProxyOriginal(ObjectWrapper):
__slots__ = ['proxy_name']
def __init__(self, subject, proxy_name):
# proxy_info attributed added directly to the
# Original instance, not the ProxyOriginal instance
self.proxy_info = 'You are proxied by {}'.format(proxy_name)
# proxy_name added to ProxyOriginal instance, since it is
# defined in __slots__
self.proxy_name = proxy_name
super(ProxyOriginal, self).__init__(subject)
if __name__ == "__main__":
original = Original()
proxy = ProxyOriginal(original, 'Proxy Overlord')
# Both statements print "The Original"
print "original.name: ", original.name
print "proxy.name: ", proxy.name
# Both statements below print
# "You are proxied by Proxy Overlord", since the ProxyOriginal
# __init__ sets it to the original object
print "original.proxy_info: ", original.proxy_info
print "proxy.proxy_info: ", proxy.proxy_info
# prints "Proxy Overlord"
print "proxy.proxy_name: ", proxy.proxy_name
# Raises AttributeError since proxy_name is only set on
# the proxy object
print "original.proxy_name: ", proxy.proxy_name
您有 - 本质 - 没有使用__slots__
。
有关,当你认为你可能需要__slots__
,你真的想使用轻型或飞锤设计模式的时间。这是当你不再想使用纯Python对象的情况。相反,要围绕阵列一个Python像对象的包装,结构或numpy的阵列。
class Flyweight(object):
def get(self, theData, index):
return theData[index]
def set(self, theData, index, value):
theData[index]= value
类状包装纸没有属性 - 它只是提供了对基础数据起作用的方法。所述方法可以减少到类方法。实际上,它可以被减少到只有函数数据的底层阵列上操作。
在原始的问题是关于一般使用情况下不仅约存储器。 所以这里应该提到的是,你还可以得到更好的性能的实例化大量的对象时 - 例如有趣解析大型文档时成对象或从数据库。
下面是创建具有一百万条目的对象树,使用槽和无槽的比较。作为参考也使用普通类型的字典的树木(Py2.7.10上OSX)时的性能:
********** RUN 1 **********
1.96036410332 <class 'css_tree_select.element.Element'>
3.02922606468 <class 'css_tree_select.element.ElementNoSlots'>
2.90828204155 dict
********** RUN 2 **********
1.77050495148 <class 'css_tree_select.element.Element'>
3.10655999184 <class 'css_tree_select.element.ElementNoSlots'>
2.84120798111 dict
********** RUN 3 **********
1.84069895744 <class 'css_tree_select.element.Element'>
3.21540498734 <class 'css_tree_select.element.ElementNoSlots'>
2.59615707397 dict
********** RUN 4 **********
1.75041103363 <class 'css_tree_select.element.Element'>
3.17366290092 <class 'css_tree_select.element.ElementNoSlots'>
2.70941114426 dict
测试类(IDENT,从槽APPART):
class Element(object):
__slots__ = ['_typ', 'id', 'parent', 'childs']
def __init__(self, typ, id, parent=None):
self._typ = typ
self.id = id
self.childs = []
if parent:
self.parent = parent
parent.childs.append(self)
class ElementNoSlots(object): (same, w/o slots)
testcode,详细模式:
na, nb, nc = 100, 100, 100
for i in (1, 2, 3, 4):
print '*' * 10, 'RUN', i, '*' * 10
# tree with slot and no slot:
for cls in Element, ElementNoSlots:
t1 = time.time()
root = cls('root', 'root')
for i in xrange(na):
ela = cls(typ='a', id=i, parent=root)
for j in xrange(nb):
elb = cls(typ='b', id=(i, j), parent=ela)
for k in xrange(nc):
elc = cls(typ='c', id=(i, j, k), parent=elb)
to = time.time() - t1
print to, cls
del root
# ref: tree with dicts only:
t1 = time.time()
droot = {'childs': []}
for i in xrange(na):
ela = {'typ': 'a', id: i, 'childs': []}
droot['childs'].append(ela)
for j in xrange(nb):
elb = {'typ': 'b', id: (i, j), 'childs': []}
ela['childs'].append(elb)
for k in xrange(nc):
elc = {'typ': 'c', id: (i, j, k), 'childs': []}
elb['childs'].append(elc)
td = time.time() - t1
print td, 'dict'
del droot