Python 3.10の新機能(その10) Dataclassでslotsが利用可能に: Python3.10の新機能 - python.jp
dataclass は、Pythonで主にデータを格納するためのクラスで、C言語などでは構造体に相当するようなデータ構造を、かんたんに定義できるようになっています。 たとえば、次の Person は、名前と年齢を格納するdataclassです。 from datacl (その1) パターンマッチ ¦ (その2) with文のネスト ¦ (その3) エラーメッセージの改善 ¦ (その4) | 演算子によるユニオン型の指定 ¦ (その5) パラメータ仕様変数 ¦ (その6) 明示的な型エイリアス ¦ (その7) ユーザ定義型ガード ¦ (その8) OpenSSL 1.1.1が必須に ¦ (その9) zip()関数に引数 strict を追加 ¦ (その10) Dataclassでslotsが利用可能に ¦ (その11) その他の変更
通常、クラスのインスタンスは、メンバー変数の名前と値を __dict__ という名前の辞書オブジェクトに格納します。
>>> classFoo:… pass…>>> foo=Foo()>>> foo.attr1=“いぬ”>>> foo.attr2=“ねこ”>>>>>> print(foo.__dict__){‘attr1’: ‘いぬ’, ‘attr2’: ‘ねこ’}しかし、クラス定義中に __slots__ という名前で、使用する属性名のシーケンスを指定すると、__dict__ 辞書が作成されなくなります。
>>> classBar:… __slots__=(‘attr1’,‘attr2’)…>>> bar=Bar()>>> bar.attr1=“うし”>>> bar.attr2=“うま”>>> bar.__dict__Traceback (most recent call last): File “<stdin>”, line 1, in <module>AttributeError: ‘Bar’ object has no attribute ‘__dict__’
スロットのメリット¶
通常、クラスのインスタンスを一つ作成すると、__dict__ に使用する辞書が一つ、新しく作成されます。
辞書オブジェクトはパフォーマンスと柔軟性重視なデータ構造で、あらかじめ余計にメモリを確保して、データの追加や削除を高速に行えるような仕組みになっています。しかし、dataclass のように、決まった形式のデータを大量に保持するようなクラスでは、めったに属性の追加や削除は行いませんから、このために確保したメモリは無駄になってしまいます。
そこで、__slots__ を指定すると、インスタンスの属性値を辞書ではなく、スロットという配列形式で格納するようになり、辞書オブジェクトの作成に必要な処理時間と、メモリ使用量を削減できます。一方、__slots__ を使ったインスタンスで属性を参照する場合、数%程度速度が低下します。
dataclassのスロット¶
__slots__ 形式の dataclass は、次のように slots=Trueを指定して定義します。
fromdataclassesimportdataclass@dataclass(slots=True)classPerson2:name:strage:intperson1=Person2(name=“パーソン太郎”,age=20)person2=Person2(name=“パーソン次郎”,age=30)実際に実行時間とメモリ使用量を測定してみましょう。
__slots__ を使用しない場合は次のとおりです。
>>> importtime,tracemalloc>>> tracemalloc.start()>>> f=time.time()>>> persons=Person(str(i),i)foriinrange(1000000)>>> print(time.time()-f)2.6621129512786865>>> current,peak=tracemalloc.get_traced_memory()>>> print(current,peak)(243329878, 243330262)処理時間は2.7秒、メモリ使用量は243MB程ですね。
__slots__ を使用するとこんな感じになります。
>>> f=time.time()>>> persons=Person2(str(i),i)foriinrange(1000000)>>> print(time.time()-f)1.7276349544525146>>> current,peak=tracemalloc.get_traced_memory()>>> print(current,peak)(139330518, 139330902)処理時間は1.7秒、メモリ使用量は139MBまで削減できました。
また、__dict__ 辞書 を持たないインスタンスでは、あたらしい属性に値を代入できません。代入すると、次のようなエラーとなります。
>>> person=Person2(“名前”,“年齢”)>>> person.addr=“じゅうしょ"Traceback (most recent call last): File “<stdin>”, line 1, in <module>AttributeError: ‘Person2’ object has no attribute ‘addr’この例の Person のようなクラスでは動的にあたらしく属性を追加することはあまりありませんので、特に問題にはなりません。むしろ、属性名間違いによるBug防止に役立つでしょう。
スロットとは?スロットのメリットdataclassのスロット
LuckyLand Slots Review and Promotions. PLAY NOW and spin your way to big wins!
This site only collects related articles. Viewing the original, please copy and open the following link:Python 3.10の新機能(その10) Dataclassでslotsが利用可能に: Python3.10の新機能 - python.jp