DataClass 3.10での機能追加(kw_only, slots)
こんにちはPython界のレアキャラです。
dataclassから機能が追加され attrsであった機能が取り込まれました。 以前書いた記事のアップデートをしておこうと思います。
TL;DR
- dataclassにkw_onlyと slotsが入った
- attrsのつかいどころ
- ボイラープレートコードを避けたい.(特にdataclassにない機能を利用したい)
- 今Python3.9 以下を使っているし、今後dataclassを使いたい.
- ドキュメントをきちんと読むと色々書いてある
kw_only
https://docs.python.org/ja/3.10/glossary.html#term-parameter キーワード専用フィールドを設定するためのもの.
>>> # クラスの全フィールドをキーワード専用にするもの >>> @dataclass(kw_only=True) ... class A: ... a: int ... b:int ... >>> a = A(1,2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: A.__init__() takes 1 positional argument but 3 were given >>> a = A(a=1,b=2) >>> a A(a=1, b=2)
ちなみに1フィールドだけ キーワード専用にしたいときは dataclasses.field
でできる。
>>> from dataclasses import field >>> @dataclass ... class B: ... x:int ... y:int = field(kw_only=True) ... >>> B(1,2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: B.__init__() takes 2 positional arguments but 3 were given >>> B(1,y=2) B(x=1, y=2) >>>
ちなみにattrsでは以下のように書く.attrsでは3.9以前のバージョンでも使える.
from attrs import define, field @define(kw_only=True) class A: a: int b: int @define class A: a: int b: int = field(kw_only=True)
slots オプション
全俺が欲しかったもの。
以前は明示的に __slots__
をつけないといけなかった。3.10からはこんな感じで書ける
from dataclasses import dataclass ## 3.9 以前のスタイル @dataclass class SlotedMessage: __slots__ = ["sender", "recipient", "body"] sender: str recipient: str body: str ## 3.10からはslotsを指定する @dataclass(slots=True) class SlotedMessage: sender: str recipient: str body: str
以前試した メモリの使用量見てみよう。
ちなみに実行前に pymperをinstallしてほしい。
pip install pympler
from typing import NamedTuple from pympler import asizeof from attrs import define from dataclasses import dataclass Message = NamedTuple("Message", [("sender", str), ("recipient", str), ("body", str)]) @dataclass class DataClassMessage: sender: str recipient: str body: str @dataclass(slots=True) class SlotedMessage: sender: str recipient: str body: str @define(auto_attribs=True, slots=True, weakref_slot=False) class AttrsMessage: sender: str recipient: str body: str if __name__ == "__main__": d = { "sender": "sender@exmaple.com", "recipient": "recipient.example.com", "body": "Hello, World!", } message = Message(**d) simple_data = DataClassMessage(**d) slotted = SlotedMessage(**d) attrs = AttrsMessage(**d) print( "NamedTuple %d, Dataclass %d, Slotted dataclass %d, attrs %d" % asizeof.asizesof(message, simple_data, slotted, attrs) )
% python aaa.py NamedTuple 272, Dataclass 528, Slotted dataclass 56, attrs 56
ここまでくると attrsのweakre_slots も入れて欲しかった気がする.
久しぶりにdataclassのドキュメントを読み返すことで発見がたくさんありました。 Python 開発者、ドキュメント書いてくれている皆様に感謝!