web-dev-qa-db-ja.com

サブクラス化Python namedtuple

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。

15
BoltzmannBrain

新しい更新:

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___はどちらにも必要ないことに注意してください。

15
Rick Teachey