Python PR

【Python】クラスのデータメンバーを明示的に指定する方法【__slots__】

記事内に商品プロモーションを含む場合があります

この記事では、クラスで使用するデータメンバーを「__slots__」を使って明示的に指定する方法を解説します。

クラスで使用するデータメンバーを明示的に指定することで、そのクラスを「軽量化」 + 「高速化」することができます。

それでは、指定する方法を見ていきましょう!

指定方法

クラスに__slots__という名前のクラス変数を定義します。__slots__には、そのクラスで使用するデータメンバーの名前を文字列で指定できます。

class Person:

    __slots__ = 'name'

    def __init__(self, name: str) -> None:
        self.name = name

使用するデータメンバーが複数存在する場合は、タプルやリストなどにまとめて指定します。

class Person:

    __slots__ = 'name', 'age'

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age

効果

__slots__を使用することで以下のような効果があります。

軽量化 + 高速化

__slots__を定義することで__dict____weakref__を自動生成しなくなります。それによりクラスを軽量化することができます。

試しに通常のクラスとデータメンバーを指定したクラスのサイズを比較してみます。

通常

class Person:

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age


print(sys.getsizeof(Person))

実行結果

1072

データクラスを指定

class Person:

    __slots__ = 'name', 'age'

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age


print(sys.getsizeof(Person))

実行結果

904

__slots__を定義するだけで100バイト以上軽量化することができました。また、属性の検索速度も大幅に改善されるようです。

ただし、__dict__や弱参照をサポートしていない点には注意してください。

動的な属性の追加の制限

__slots__を定義したクラスでは、動的に属性を追加することができなくなります。

一見デメリットのように感じるかもしれませんが、属性を後から追加する予定がないクラスの場合ではむしろ安全性が増します。

class Person:

    __slots__ = 'name', 'age'

    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age


mike = Person('Mike', 20)

# __slots__にない属性を追加
mike.gender = 'man'

実行結果

Traceback (most recent call last):
  File "main.py", line 13, in 
    mike.gender = 'man'
AttributeError: 'Person' object has no attribute 'gender'

これにより変数名間違いなどの心配もなくなります。

まとめ

この記事では、クラスのデータメンバーを明示的に指定する方法を解説しました。

__slots__を使うことでクラスを「軽量化」+「高速化」することができます。__dict__や弱参照を使わないかつ、動的に変数を追加しない場合は積極的に使っていきましょう!

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ