Pythonの名前付きタプルは、軽量で不変のデータクラスとして非常に役立ちます。辞書ではなく簿記パラメータに使用するのが好きです。単純なdocstringやデフォルト値など、さらに多くの機能が必要な場合は、namedtupleをクラスに簡単にリファクタリングできます。ただし、namedtupleから継承するクラスを見てきました。彼らはどのような機能を獲得し、どのようなパフォーマンスを失っていますか?たとえば、私はこれを次のように実装します
from collections import namedtuple
class Pokemon(namedtuple('Pokemon', 'name type level')):
"""
Attributes
----------
name : str
What do you call your Pokemon?
type : str
grass, rock, electric, etc.
level : int
Experience level [0, 100]
"""
__slots__ = ()
Attrsをきれいに文書化できる唯一の目的で、__slots__
は__dict__
の作成を防ぐために使用されます(名前付きタプルの軽量性を維持します)。
パラメータを文書化するための軽量データクラスの推奨事項はありますか?注Python 2.7。
新しい更新:
python 3.6+では、新しい型付き構文を使用して_typing.NamedTuple
_を作成できます。新しい構文は、通常のpythonクラス作成機能をすべてサポートします(ドキュメント文字列、多重継承、デフォルトの引数、メソッドなどは3.6.1以降で利用可能です):
_import typing
class Pokemon(MyMixin, typing.NamedTuple):
"""
Attributes
----------
name : str
What do you call your Pokemon?
type : str
grass, rock, electric, etc.
level : int
Experience level [0, 100]
"""
name: str
type: str
level: int = 0 # 3.6.1 required for default args
def method(self):
# method work
_
このバージョンで作成されたクラスオブジェクトは、元の_collections.namedtuple
_、 いくつかの詳細を除いて とほぼ同等です。
古い名前付きタプルと同じ構文を使用することもできます。
_Pokemon = typing.NamedTuple('Pokemon', [('name', str), ('type', str), ('level', int)])
_
元の回答
短い答え: いいえ、Python <3.5 を使用している場合を除く)
P3 docs は、計算フィールド(つまり、記述子)を追加する必要がない限り、namedtuple
のサブクラス化が標準的なアプローチとは見なされないことをかなり明確に示唆しているようです。これは、docstringを直接更新できるためです(3.5以降では書き込み可能です!)。
サブクラス化は、新しく保存されたフィールドを追加する場合には役立ちません。代わりに、単に_
_fields
_属性から新しい名前付きタプル型を作成します...Docstringは、_
__doc__
_フィールドに直接割り当てることでカスタマイズできます...
更新:
Pythonの最新バージョンの軽量データクラスには、他にも魅力的な可能性がいくつかあります。
1つは _types.SimpleNamespace
_(Python 3.3以降) です。 namedtuple
のように構造化されているわけではありませんが、構造は必ずしも必要ではありません。
SimpleNamespace
について1つ注意する必要があります。デフォルトでは、クラスをインスタンス化するときにフィールド名を明示的に指定する必要があります。ただし、これはsuper().__init__
を呼び出すことでかなり簡単に回避できます。
_from types import SimpleNamespace
class Pokemon(SimpleNamespace):
"""
Attributes
----------
name : str
What do you call your Pokemon?
type : str
grass, rock, electric, etc.
level : int
Experience level [0, 100]
"""
__slots__ = ("name", "type", "level")
# note that use of __init__ is optional
def __init__(self, name, type, level):
super().__init__(name=name, type=type, level=level)
_
別の興味深いオプション- Python 3.7)で利用可能 -は _dataclasses.dataclass
_ です( PEP 557も参照) ):
_from dataclasses import dataclass
@dataclass
class Pokemon:
__slots__ = ("name", "type", "level")
name: str # What do you call your Pokemon?
type: str # grass, rock, electric, etc.
level: int = 0 # Experience level [0, 100]
_
これらの提案は両方ともデフォルトで変更可能であり、___slots__
_はどちらにも必要ないことに注意してください。