利用に__slots__?
-
19-08-2019 - |
質問
目的は何か __slots__
Pythonでは、特につの場合いたいと思利用できません。
解決
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
Pythonなオブジェクトだこの間違い(しかし、問題がなマニフェストが、オブジェクトを取るような。
>>> 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%より速いブ3.5Ubuntu.
>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342
Python2はWindowsしていま測定では約15%になります。
を利用する理由 __slots__
:メモリの貯蓄
もう一つの目的の __slots__
軽空間記憶している各オブジェクトインスタンス。
のスペースに保存用
__dict__
できます。
SQLAlchemy属性 多くのメモリの節約 __slots__
.
を検証するこのAnaconda分布のPython2.7Ubuntu Linux、 guppy.hpy
(通称heapy) sys.getsizeof
, のサイズクラスのインスタンスな __slots__
宣言は、何といっても、64バイトまでとなります。ることは ない などの __dict__
.まPythonのためのぐさの評価は、再び、 __dict__
そうしないという存在では参照されるが、授業のデータの有無にかかわらず、通常のどちらがいいでしょうか?が呼び出されるとともに __dict__
属性が最小限280バイトします。
これに対し、クラスのインスタンス __slots__
宣言されて ()
(データ)は16バイトは、56総バイスロット、64ます。
64ビットはPythonのかを説明するメモリ消費量のバイトをPython2.7 3.6、 __slots__
や __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
いずれか小さいdicts Python3にしていく __slots__
規模インスタンスを存メモリは、大きな理由でも使いたい __slots__
.
だけで完成度の上記のい場合がありますので注意して一時コスロットのクラスの名前空間の64バイトをPython2は、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__
からの親の場合は制御の両親は、空のスロットに、refactorへの抽象化:
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__
を創造できるよう退off __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'
まん してい てスロットできるの追加と削除し、その後はな問題を引き起こす.
したいと願うようになっている肢こちら:だを構成する mixins または使用 抽象基底クラス, 思意のインスタンスが生成され、空の __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__
課題別のクラスがない(できない追加しない場合にスロットレイアウトのと同一です。(私の学習に興味をもっている者であることはいかがでしょうか。) - を回避したい場合はサブクラスは可変長builtinsのように、タプル、またはstrやしたい属性を追加します。
- 避けることばを提供するデフォルト値で経由クラス属性のためのインスタンス変数.
ることができる絵の一層の注意から __slots__
書類(3.7dev docsに現在), また、私ども大きく最近の貢献です。
批評のその他の回答
現在のトップ応答挙げ時代遅れの情報はなかなか手波のマークの一部の重要な要素がある。
い"のみを使用 __slots__
スをインスタンス化する際に多くのオブジェ"
し見積もり:
"と思った利用
__slots__
だよりインスタンスを生成する景色は駅の屋根だけという、何百、何千人ものオブジェクトと同じクラスです。"
抽象基底クラスでしっかり果たしていきたいと考え、 collections
モジュールなインスタンスを生成し __slots__
宣言されました。
なぜですか?
本サイトのご利用に拒否 __dict__
または __weakref__
創造も必要によってご利用になれない親ます。
__slots__
に貢献する再利用性の作成時にインタフェースmixins.
るが、すでに多くの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>
ようなので注意してください。では解決問題です。
批判するまで月2日2016年度)受付回答
最初の段落の半分の短い説明は、半分に予測しやすいものにするかこちらのはみっという問いに対する答え
の適切な利用に関す
__slots__
は、保存スペースオブジェクト。を有する動的辞書名またを設定できる追加の属性体自身の自己責任でなされるものである静的構造できない追加後ます。こに保存する架空の辞べてのオブジェクトを使用するスロット
後半は希望的観測としては、のマーク:
なることが多いので、有益な最適化が全く不要な場合はPythonインタプリタがった動くことにするための辞があった追加のオブジェクトです。
Python実際にはそこだけの作成 __dict__
ときにアクセスが、多くのオブジェクトのデータはかなりば.
第二項の規定oversimplifies、ミスを実際に理由を回避 __slots__
.以下に示します ない 実際の理由を避けるスロット( 実際の 理由は、自分の答えます。):
その変化の挙動はスロットができる虐待の制御によるフリークおよび静的タイピングweenies.
そして、その議その他の方法で達成するのが僕の目標はPythonではな議論といい __slots__
.
第三項の規定は希望的観測かがえます。とほとんどの場合、これは、マークのコンテンツのanswererなかったものの著者への弾薬のための批判のサイトです。
メモリ使用の証拠
を通常のオブジェクトにスロット付きオブジェクト
>>> 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
...
この歴史のPythonから 統一種およびクラスをPython2.2
場合はサブクラス内蔵タイプ、余分のスペースが自動的に追加され、インスタンスを調整
__dict__
や__weakrefs__
.(__dict__
が初期化されませんでしまい、なんか気の空の辞書のための各インスタンスを作成します.) 必要がない場合はこの余分のスペースに追加することができますの言葉"__slots__ = []
"をクラスです。
他のヒント
あなたは、同じクラスのオブジェクトの多く(数百、数千の)インスタンス化しようとしている場合__slots__
使用するとよいでしょう。 <=>専用メモリ最適化ツールとして存在します。
これは、属性の作成を拘束するため<=>使用することを非常に落胆だし、一般的に、あなたは、Pythonの他のいくつかのイントロスペクション機能と一緒に、それはピクルスを壊すので、それを避けたい。
各Pythonオブジェクトは、他のすべての属性を含む辞書である__dict__
atttributeを有しています。例えばあなたはself.attr
入力のpythonは、実際にself.__dict__['attr']
やっています。あなたは属性を格納するための辞書を使用して想像できるように、それをアクセスするためのいくつかの余分なスペース&時間がかかります。
__slots__
使用する場合、しかし、そのクラス用に作成された任意のオブジェクトは、<=>属性を持っていません。代わりに、すべての属性へのアクセスは、ポインタ経由で直接実行されます。
Cスタイルの構造ではなく、本格的なクラスをしたいのであれば、あなたは、オブジェクトのサイズを圧縮&属性アクセス時間を短縮するための<=>使用することができます。良い例は、属性のX&Yを含むPointクラスです。あなたはポイントをたくさん持ってしようとしている場合は、一部のメモリを節約するために<=>使用して試すことができます。
は、他の回答に加えて、ここで使用した例である__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']
(それがまだない場合は、新しいスタイルのクラスをし、あなたのクラスを作る)だから、<=>実装し、それだけで余分なラインを取ります。あなたがhref="http://dev.svetlyak.ru/using-slots-for-optimisation-in-python-en/"を を、それが必要になった場合ならば、カスタム・ピクルス・コードを記述することを犠牲にします。
スロットは、ライブラリ関数呼び出しを行うときに「という名前のメソッドディスパッチ」を排除するために呼び出すために非常に便利です。これはSWIG ドキュメントの中で言及されています。スロットを使用して、一般的に呼ばれる機能のための機能のオーバーヘッドを削減したい、高いパフォーマンスライブラリの場合ははるかに高速です。
さて、これは直接のOPの質問に関連していなくてもよいです。それはそれはオブジェクト上のスロットの構文を使用するよりも、建物の拡張により関連しています。しかし、それは、スロットとその背後にある理由のいくつかの用途のために絵を完成助けるん。
クラスのインスタンスの属性は、3つのプロパティがあります。例えば、属性の名前、および属性の値を
での の通常の属性アクセスのを、インスタンスは辞書として機能し、属性の名前は、値を調べることで、辞書のキーとして機能します。
のインスタンス(属性) - >値の
での の__ slots__アクセスのの、属性の名前が辞書として機能し、インスタンスが値を調べる辞書でキーとして機能します。
の属性(インスタンス) - >値の
の のFlyweightパターンののでは、属性の名前は、インスタンスを探している辞書でキーとして辞書と値の行為として機能します。
の属性(値) - >例の
非常に簡単な例 __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 や obj2 独自の x や y 属性および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__
の別のややあいまいな用途はPEAKプロジェクトの一部かつて、ProxyTypesパッケージからオブジェクトプロキシに属性を追加することです。そのObjectWrapper
プロキシに別のオブジェクトを許可しますが、プロキシになるオブジェクトとのすべてのやり取りを傍受します。これは非常に一般的に使用されていない(そしてPythonの3のサポート)はありませんが、我々はスレッドセーフを使用して、ioloopを介してプロキシオブジェクトへのすべてのアクセスをバウンス竜巻に基づく非同期実装の周りにスレッドセーフなブロッキングラッパーを実装するためにそれを使用していますconcurrent.Future
同期して結果を返すためにオブジェクトます。
デフォルトでは、プロキシオブジェクトへの任意の属性へのアクセスは、あなたのプロキシになるオブジェクトからの結果が得られます。プロキシオブジェクトに属性を追加する必要がある場合は、<=>を使用することができます。
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__
のための使用を。
あなたが<=>必要かもしれないと思う時間のために、あなたは実際の軽量またはフライ級のデザインパターンを使用します。これらはあなたがもはや純粋にPythonのオブジェクトを使用したいない場合もあります。代わりに、配列、構造体、またはnumpyの配列の周りのPythonオブジェクトのようなラッパーを望んます。
class Flyweight(object):
def get(self, theData, index):
return theData[index]
def set(self, theData, index, value):
theData[index]= value
クラスのようなラッパーには属性がありません - それだけで、基礎となるデータに作用するメソッドを提供します。メソッドは、クラスメソッドに減少させることができます。確かに、それだけでデータの基になる配列上で動作して機能するために減少させることができた。
元の質問は、メモリについてだけでなく、一般的な使用例についてでした。 興味深い例えば - だから、のパフォーマンスのオブジェクトを大量にインスタンス化するときにも良くなることをここで言及されるべきですオブジェクトへ、またはデータベースから大規模な文書を解析するときます。
ここでスロットを使用して、百万のエントリを持つオブジェクトツリーを作成し、スロットなしの比較です。また、基準木(OSX上Py2.7.10)のために普通dictsを使用してパフォーマンスとして:
********** 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、スロットからアパート):
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