他の人が述べたように、定義する唯一の理由は__slots__、定義済みの属性セットを持つ単純なオブジェクトがあり、それぞれに辞書を持ち歩きたくない場合に、メモリを節約することです。もちろん、これは、多くのインスタンスを持つ予定のクラスに対してのみ意味があります。
節約はすぐには明らかではないかもしれません -- 考慮してください...:
>>> class NoSlots(object): pass
...
>>> n = NoSlots()
>>> class WithSlots(object): __slots__ = 'a', 'b', 'c'
...
>>> w = WithSlots()
>>> n.a = n.b = n.c = 23
>>> w.a = w.b = w.c = 23
>>> sys.getsizeof(n)
32
>>> sys.getsizeof(w)
36
このことから、スロットありのサイズはスロットなしのサイズよりも大きいように見えます。sys.getsizeofしかし、辞書などの「オブジェクトの内容」を考慮していないため、これは間違いです。
>>> sys.getsizeof(n.__dict__)
140
dict だけで 140 バイトかかるため、明らかに、「32 バイト」オブジェクトnが取ると主張されているのは、各インスタンスに関係するすべてを考慮していないことです。pimplerなどのサードパーティの拡張機能を使用すると、より良い仕事をすることができます:
>>> import pympler.asizeof
>>> pympler.asizeof.asizeof(w)
96
>>> pympler.asizeof.asizeof(n)
288
これは、 によって節約されるメモリ フットプリントをより明確に示しています__slots__。この場合のような単純なオブジェクトの場合、200 バイトより少し少なく、オブジェクト全体のフットプリントのほぼ 2/3 です。最近では、ほとんどのアプリケーションにとって 1 メガバイトは多かれ少なかれそれほど重要ではないため、これは__slots__、一度に数千のインスタンスしか持たない場合は、気にする価値がないことも示しています。ただし、何百万ものインスタンスにとって、それは確かに非常に重要な違いをもたらします. また、微視的なスピードアップも得られます (部分的には、 を使用した小さなオブジェクトのキャッシュの使用が改善されるためです__slots__):
$ python -mtimeit -s'class S(object): __slots__="x","y"' -s's=S(); s.x=s.y=23' 's.x'
10000000 loops, best of 3: 0.37 usec per loop
$ python -mtimeit -s'class S(object): pass' -s's=S(); s.x=s.y=23' 's.x'
1000000 loops, best of 3: 0.604 usec per loop
$ python -mtimeit -s'class S(object): __slots__="x","y"' -s's=S(); s.x=s.y=23' 's.x=45'
1000000 loops, best of 3: 0.28 usec per loop
$ python -mtimeit -s'class S(object): pass' -s's=S(); s.x=s.y=23' 's.x=45'
1000000 loops, best of 3: 0.332 usec per loop
しかし、これは Python のバージョンに多少依存します (これらは私が 2.5 で繰り返し測定した数値です。2.6 では、属性を設定するための相対的な利点が大きくなっていますが、属性を設定__slots__するための相対的な利点はまったくありません。実際、それを取得するための小さな欠点です)。
さて、継承に関して: インスタンスが辞書なしであるためには、その継承チェーンの上のすべてのクラスも辞書なしのインスタンスを持つ必要があります。dict-less インスタンスを持つクラスは__slots__、 とほとんどの組み込み型を定義するクラスです (インスタンスに dict がある組み込み型は、関数などの任意の属性をインスタンスに設定できるクラスです)。スロット名の重複は禁止されていませんが、スロットは継承されるため、役に立たず、メモリを浪費します:
>>> class A(object): __slots__='a'
...
>>> class AB(A): __slots__='b'
...
>>> ab=AB()
>>> ab.a = ab.b = 23
>>>
aご覧のとおり、ABインスタンスに属性を設定できます。ABそれ自体は slot のみを定義しますが、からbslot を継承します。継承されたスロットを繰り返すことは禁止されていません:aA
>>> class ABRed(A): __slots__='a','b'
...
>>> abr=ABRed()
>>> abr.a = abr.b = 23
しかし、少しメモリを浪費します:
>>> pympler.asizeof.asizeof(ab)
88
>>> pympler.asizeof.asizeof(abr)
96
だから、それをする理由は本当にありません。