__slots__ はクラスの特別な属性であり、インスタンスの許可された属性のセットを制限し、メモリを節約し、属性へのアクセスを高速化します。__slots__ の使用は、同様のオブジェクトが多数存在する場合に特に有効です。
問題の背景:
__slots__ の登場は、各Pythonオブジェクトのインスタンスが属性の辞書(__dict__)を持つことに起因しています。これは便利ですが、メモリを消費します。フィールドの少ない100万のオブジェクトを扱う際には、かなりのオーバーヘッドが発生します。
問題:
通常のクラスのインスタンスは動的に拡張できるため便利ですが、非効率的です。__slots__ を使用すると、新しい属性の動的追加を制限し、インスタンス属性の辞書を排除し、メモリを節約し、アクセスを高速化します。
解決策:
許可されたフィールドのリストを __slots__ 属性に記述します:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y p = Point(1, 2) p.z = 3 # AttributeError: 'Point' オブジェクトには 'z' 属性がありません
主な特徴:
slots を持つクラスのインスタンスを作成し、その後リストにない属性を追加できますか?
いいえ。リストにない属性を追加しようとすると、AttributeError が発生します。これはオブジェクトの拡張性に制限を課します。
slots を持つクラスを継承し、新しいフィールドを追加できますか?
はい、ただし各子クラスは自分の slots を宣言しなければなりません。この場合、親と現在の slots は統合されます。ただし、子クラスで slots を宣言しないと、子に再び dict が出現します!
slots は不変(immutable)タイプに対して機能しますか?
はい、ただしスロットオブジェクトを不変にするために追加の手段を実装する必要があります(たとえば、setterなしのプロパティを介して)。
点のための通常のクラス:
class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
利点:
欠点:
スロットを使用した同様のクラス:
class Point: __slots__ = ('x', 'y') def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]
利点:
欠点: