ProgrammingバックエンドPython開発者

Pythonのクラスにおける__slots__とは何か、それはなぜ必要で、どのような制限があるのか?

Hintsage AIアシスタントで面接を突破

回答。

__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' 属性がありません

主な特徴:

  • dictweakref がデフォルトでないため、メモリを節約します。
  • 許可されたフィールドの厳密なセットを定義します。
  • プリアロケートされたスロットのおかげで属性へのアクセスが高速化され、辞書内を検索する必要がありません。

罠のある質問。

slots を持つクラスのインスタンスを作成し、その後リストにない属性を追加できますか?

いいえ。リストにない属性を追加しようとすると、AttributeError が発生します。これはオブジェクトの拡張性に制限を課します。

slots を持つクラスを継承し、新しいフィールドを追加できますか?

はい、ただし各子クラスは自分の slots を宣言しなければなりません。この場合、親と現在の slots は統合されます。ただし、子クラスで slots を宣言しないと、子に再び dict が出現します!

slots は不変(immutable)タイプに対して機能しますか?

はい、ただしスロットオブジェクトを不変にするために追加の手段を実装する必要があります(たとえば、setterなしのプロパティを介して)。

一般的なエラーとアンチパターン

  • 子クラスで slots を宣言しないと、メモリ効率が損なわれる。
  • マルチインヘリタンスが存在する場合、slots の動作を期待すること — 衝突やエラーが発生する可能性があります。
  • 追加の手段を用いないインスタンスをシリアル化しようとすると、標準の手段が困難なことがあります(たとえば、pickle は dict を必要とします)。

実例

ネガティブケース

点のための通常のクラス:

class Point: def __init__(self, x, y): self.x = x self.y = y points = [Point(i, i) for i in range(1_000_000)]

利点:

  • 柔軟性 — どのような属性でも追加可能。
  • 初心者にとってわかりやすい。

欠点:

  • タスクマネージャーはメモリ消費がかなり高いことを示します(最大+20-30%)。

ポジティブケース

スロットを使用した同様のクラス:

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)]

利点:

  • 100万のオブジェクトで最大30%のメモリ節約。
  • フィールドへのアクセスが速くなります。

欠点:

  • オブジェクトが硬直的になり、動的に新しい属性を追加できなくなります。