Keep on moving

あんまりまとまってないことを書きますよ

dataclassと __slots__ について調べた

対象バージョン Python 3.7以降

TL;DR

  • dataclassでも __slots__ を使える
  • __slots__ をつかうとpropertyの追加ができなくなる(自由度が下るが、コードをおいやすくなる)

slots とは

docs.python.org

__slots__ を使うと、(プロパティのように) データメンバを明示的に宣言し、 (明示的に __slots__ で宣言しているか親クラスに存在しているかでない限り) __dict____weakref__ を作成しないようにできます。 __dict__ を使うのに比べて、節約できるメモリ空間はかなり大きいです。 属性探索のスピードもかなり向上できます。

ということらしい。

dataclassの動作

dataclassを自分で使うときは私の用途だと関数の返り値/引数とかで使うときがおおいのでメモリ空間の節約できると便利だと思ってしらべてみました。 また、データ型の表現で使うときはプロパティの追加ができないほうが便利かなーと。

>>> import dataclasses
>>> @dataclasses.dataclass
... class A:
...    b: int
>>> a = A(1)
>>> a.b
1
>>> a.c =2 # propertyを追加できる
>>> a.c
2
>>> dir(a) # __dict__ や __weakref__ が作成される
['__annotations__', '__class__', '__dataclass_fields__', '__dataclass_params__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'b', 'c']

というわけでdataclassでは __slots__ が有効ではないみたい。 dataclassの動作を見てる感じだと、__slots__ を有効にするオプションはないみたい docs.python.org

dataclss with __slots__

www.python.org PEP-557では自動的に追加することは一旦やめる的なことが書かれている。 実際に使うにはこんならしい。

>>> @dataclasses.dataclass
... class B:
...   __slots__ = ('b',) # __slots__ 追加
...   b: int
... 
>>> b = B(2)
>>> dir(b)
['__annotations__', '__class__', '__dataclass_fields__', '__dataclass_params__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'b']
>>> b.d =3 # propetyの追加不可
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'B' object has no attribute 'd'

まとめ

ということで dataclassをつかったクラスでも __slots__ を定義すれば設定できる。ただ、これ何回も書くのめんどいので なんかいも設定するならば attrs 使ったほうがよさそう。明日はattrsを使ったパターンを書こうと思う