PEP-557 Python標準ライブラリにデータクラスを導入しました。これは基本的にcollections.namedtuple
およびtyping.NamedTuple
。そして今、私はnamedtupleがより良い解決策であるユースケースをどのように分離するのか疑問に思っています。
もちろん、必要な場合はすべてのクレジットがdataclass
に割り当てられます。
property
デコレーター、管理可能な属性データクラスの利点は、同じPEPで簡単に説明されています: なぜnamedtupleを使用しないのか 。
しかし、namedtuplesの反対の質問はどうでしょうか。なぜデータクラスを使用しないのですか?おそらくnamedtupleはパフォーマンスの観点からは優れていると思いますが、まだ確認されていません。
次の状況を考えてみましょう。
静的に定義されたフィールド、タイプヒンティング、および名前付きアクセスを備えた小さなコンテナにページディメンションを保存します。それ以上のハッシュ、比較などは必要ありません。
NamedTupleアプローチ:
from typing import NamedTuple
PageDimensions = NamedTuple("PageDimensions", [('width', int), ('height', int)])
DataClassアプローチ:
from dataclasses import dataclass
@dataclass
class PageDimensions:
width: int
height: int
どのソリューションが望ましいのですか?
追伸質問は その1 の複製ではありません。ここではのケースについて尋ねているためnamedtupleは、差ではなく、優れています(尋ねる前にドキュメントとソースを確認しました)
それはあなたのニーズ次第です。それぞれに利点があります。
PyCon 2018のDataclassesの説明はこちら Raymond Hettinger-Dataclasses:すべてのコードジェネレーターを終了するコードジェネレーター
Dataclassでは、Namedtupleのようにすべての実装がPythonで記述されていますが、NamedtupleはTupleから継承されるため、これらの動作はすべて無料です。 Tuple構造はCで記述されているため、Namedtupleの標準メソッド(ハッシュ、比較など)の方が高速です。
しかし、DataclassはTupleに基づくNamedtupleとしてdictに基づいています。これによると、これらの構造を使用することの利点と欠点があります。たとえば、NamedTupleではスペース使用量は少なくなりますが、Dataclassでは時間アクセスが速くなります。
私の実験をご覧ください:
In [33]: a = PageDimensionsDC(width=10, height=10)
In [34]: sys.getsizeof(a) + sys.getsizeof(vars(a))
Out[34]: 168
In [35]: %timeit a.width
43.2 ns ± 1.05 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [36]: a = PageDimensionsNT(width=10, height=10)
In [37]: sys.getsizeof(a)
Out[37]: 64
In [38]: %timeit a.width
63.6 ns ± 1.33 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
ただし、NamedTupleの属性の数を増やしても、各属性に対して属性の名前を持つプロパティが作成されるため、アクセス時間は同じままです。たとえば、この場合、新しいクラスの名前空間の一部は次のようになります。
from operator import itemgetter
class_namespace = {
...
'width': property(itemgetter(0, doc="Alias for field number 0")),
'height': property(itemgetter(0, doc="Alias for field number 1"))**
}
どの場合にnamedtupleがより良い選択ですか?
データ構造が不変、ハッシュ可能、反復可能、アンパック可能、同等である必要がある場合、NamedTupleを使用できます。たとえば、データ構造の継承の可能性など、より複雑なものが必要な場合は、Dataclassを使用します。
一般的なプログラミングでは、不変にすることができるものはすべて不変でなければなりません。次の2つが得られます。
そのため、データが不変の場合、データクラスの代わりに名前付きのタプルを使用する必要があります
私はコメントでそれを書きましたが、ここでそれについて言及します:特にデータクラスのfrozen=True
と重複があることは間違いありませんが、名前付きタプルに属するアンパックなどの機能はまだあります。常に不変である-名前付きタプルをそのように削除するとは思えない