web-dev-qa-db-ja.com

データクラスと型指定NamedTupleの主な使用例

短編小説

PEP-557 Python標準ライブラリにデータクラスを導入しました。これは基本的にcollections.namedtupleおよびtyping.NamedTuple。そして今、私はnamedtupleがより良い解決策であるユースケースをどのように分離するのか疑問に思っています。

NamedTupleに対するデータクラスの利点

もちろん、必要な場合はすべてのクレジットがdataclassに割り当てられます。

  • 可変オブジェクト
  • 継承サポート
  • propertyデコレーター、管理可能な属性
  • すぐに生成されるメソッド定義またはカスタマイズ可能なメソッド定義

データクラスの利点は、同じPEPで簡単に説明されています: なぜnamedtupleを使用しないのか

Q: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は、ではなく、優れています(尋ねる前にドキュメントとソースを確認しました)

15

それはあなたのニーズ次第です。それぞれに利点があります。

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つが得られます。

  1. プログラムを読みやすくする-値が変更されることを心配する必要はありません。一度インスタンス化されると、変更されることはありません(名前付きタプル)
  2. 奇妙なバグの可能性が少ない

そのため、データが不変の場合、データクラスの代わりに名前付きのタプルを使用する必要があります

私はコメントでそれを書きましたが、ここでそれについて言及します:特にデータクラスのfrozen=Trueと重複があることは間違いありませんが、名前付きタプルに属するアンパックなどの機能はまだあります。常に不変である-名前付きタプルをそのように削除するとは思えない

4
maor10