1. ホーム
  2. python

namedtupleとNamedTupleの違いは何ですか?

2023-10-11 12:39:41

質問

その typing モジュールドキュメント は、以下の2つのコードスニペットが同等であると言っています。

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int

from collections import namedtuple

Employee = namedtuple('Employee', ['name', 'id'])

これらは全く同じものなのでしょうか、そうでないとしたら、2つの実装の違いは何なのでしょうか?

どのように解決するのですか?

サブクラス化によって生成された型 typing.NamedTuple とは、同じように collections.namedtuple と同じですが __annotations__ , _field_types_field_defaults 属性が追加されました。生成されたコードは、Pythonの何も現在これらの型付けに関連する属性に作用しないので、すべての実用的な目的のために、同じ動作をします(あなたのIDEはそれらを使用するかもしれませんが)。

開発者としては typing モジュールを使うことで、より自然な宣言的インターフェイスが可能になります。

  • フィールドのデフォルト値を簡単に指定することができます ( 編集 : Python 3.7では collections.namedtuple が追加されました。 defaults キーワード が追加されたので、これはもはや利点ではありません。 )
  • 型名を2回繰り返す必要はありません("Employee")。
  • 型を直接カスタマイズできる (例: docstring やいくつかのメソッドを追加する)

前と同じように、あなたのクラスは tuple のサブクラスとなり、インスタンスは tuple のインスタンスになります。 興味深いことに、あなたのクラスは NamedTuple . その理由を知りたければ、実装の詳細について読んでみてください。

from typing import NamedTuple

class Employee(NamedTuple):
    name: str
    id: int

Python <= 3.8での挙動

>>> issubclass(Employee, NamedTuple)
False
>>> isinstance(Employee(name='guido', id=1), NamedTuple)
False

typing.NamedTuple はクラスで、これは メタクラス とカスタム __new__ を使ってアノテーションを処理し、それを に委ねます。 collections.namedtuple を構築して返すために、とにかく、型 . 小文字の名前の規則から推測されるように collections.namedtuple は型/クラスではなく、ファクトリー関数です。 これは Python のソースコードの文字列を構築し、次に exec を呼び出すことで動作します。は 生成されたコンストラクタは、名前空間から抜き出された の 3 引数呼び出しに含まれます。 type の3つの引数でクラスを構築して返します。これは、上で見た奇妙な継承の破綻を説明するものです。 NamedTuple はメタクラスを使うことで 異なる メタクラスを使用してクラスオブジェクトをインスタンス化します。

Pythonでの動作 >= 3.9

typing.NamedTuple から変更されます。 class から def .

>>> issubclass(Employee, NamedTuple)
TypeError: issubclass() arg 2 must be a class or tuple of classes
>>> isinstance(Employee(name="guido", id=1), NamedTuple)
TypeError: isinstance() arg 2 must be a type or tuple of types

による多重継承 NamedTuple を使った多重継承は禁止されました(そもそも正常に動作していませんでした)。

参照 bpo40185 / GH-19371 を変更しました。