Python

【Python】クラスのデータメンバーを明示的に指定する方法【__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__を自動生成しなくなります。それによりクラスを軽量化することができます。

例えば、以下のようなクラスに__slots__を定義すると、

class Person:

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


print(sys.getsizeof(Person))

実行結果

1072

100バイト以上軽量化することができました。

class Person:

    __slots__ = 'name', 'age'

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


print(sys.getsizeof(Person))

実行結果

904

また、属性の検索速度も大幅に改善されるようです。

ただし、__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__を使うことでクラスを「軽量化」+「高速化」することができます。

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