簡単な方法でドキュメント文字列を名前付きタプルに追加することは可能ですか?
はい、いくつかの点で。
サブクラスのtyping.NamedTuple - Python 3.6+
Python 3.6では、docstring (および注釈!) を使用して、class
定義を直接使用できます。typing.NamedTuple
from typing import NamedTuple
class Card(NamedTuple):
"""This is a card type."""
suit: str
rank: str
Python 2 と比較して、空の宣言__slots__
は必要ありません。Python 3.8 では、サブクラスであっても必要ありません。
宣言__slots__
を空にすることはできないことに注意してください。
Python 3 では、namedtuple のドキュメントを簡単に変更することもできます。
NT = collections.namedtuple('NT', 'foo bar')
NT.__doc__ = """:param str foo: foo name
:param list bar: List of bars to bar"""
これにより、ヘルプを呼び出すときにそれらの意図を表示できます。
Help on class NT in module __main__:
class NT(builtins.tuple)
| :param str foo: foo name
| :param list bar: List of bars to bar
...
これは、Python 2 で同じことを達成するのが困難であったことに比べれば、非常に簡単です。
パイソン 2
Python 2 では、次のことが必要になります。
- 名前付きタプルをサブクラス化し、
- 宣言する
__slots__ == ()
宣言__slots__
は、ここでの他の回答が見逃している重要な部分です。
宣言しない__slots__
と、変更可能なアドホック属性がインスタンスに追加され、バグが発生する可能性があります。
class Foo(namedtuple('Foo', 'bar')):
"""no __slots__ = ()!!!"""
そしていま:
>>> f = Foo('bar')
>>> f.bar
'bar'
>>> f.baz = 'what?'
>>> f.__dict__
{'baz': 'what?'}
各インスタンスは、アクセス時に個別の__dict__
whenを作成し__dict__
ます (__slots__
がなくても機能が妨げられることはありませんが、タプルの軽量性、不変性、および宣言された属性はすべて、名前付きタプルの重要な機能です)。
__repr__
コマンドラインでエコーされるものを同等のオブジェクトにする場合は、も必要です。
NTBase = collections.namedtuple('NTBase', 'foo bar')
class NT(NTBase):
"""
Individual foo bar, a namedtuple
:param str foo: foo name
:param list bar: List of bars to bar
"""
__slots__ = ()
__repr__
ベースの namedtuple を別の名前で作成する場合は、次のような aが必要です (上で name 文字列引数を使用して行ったように'NTBase'
):
def __repr__(self):
return 'NT(foo={0}, bar={1})'.format(
repr(self.foo), repr(self.bar))
repr をテストするには、インスタンス化してから、パスが等しいかどうかをテストしますeval(repr(instance))
nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt
ドキュメントの例
ドキュメントには、次のような例も示されて__slots__
います-私は自分のdocstringをそれに追加しています:
class Point(namedtuple('Point', 'x y')):
"""Docstring added here, not in original"""
__slots__ = ()
@property
def hypot(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
def __str__(self):
return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
...
上記のサブクラス__slots__
は空のタプルに設定します。これにより、インスタンス ディクショナリが作成されなくなり、メモリ要件を低く抑えることができます。
これはインプレース使用法を示しています (ここで別の回答が示唆しているように) が、デバッグしている場合、メソッド解決順序を見るとインプレース使用法が混乱する可能性があることに注意してくださいBase
。ベースという名前のタプルの場合:
>>> Point.mro()
[<class '__main__.Point'>, <class '__main__.Point'>, <type 'tuple'>, <type 'object'>]
# ^^^^^---------------------^^^^^-- same names!
を使用するクラスからサブクラス化するときに が作成__dict__
されないようにするには、サブクラスでも宣言する必要があります。の使用に関するその他の注意事項については、この回答__slots__
も参照してください。