91

簡単な方法でドキュメント文字列を名前付きタプルに追加することは可能ですか?

私は試した

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
"""
A point in 2D space
"""

# Yet another test

"""
A(nother) point in 2D space
"""
Point2 = namedtuple("Point2", ["x", "y"])

print Point.__doc__ # -> "Point(x, y)"
print Point2.__doc__ # -> "Point2(x, y)"

しかし、それはそれをカットしません。他の方法で行うことは可能ですか?

4

10 に答える 10

74

__doc__Python 3 では、型の属性が書き込み可能であるため、ラッパーは必要ありません。

from collections import namedtuple

Point = namedtuple('Point', 'x y')
Point.__doc__ = '''\
A 2-dimensional coordinate

x - the abscissa
y - the ordinate'''

これは、ヘッダーの後に docstring が続く標準クラス定義に密接に対応しています。

class Point():
    '''A 2-dimensional coordinate

    x - the abscissa
    y - the ordinate'''
    <class code>

これは Python 2 では機能しません。

AttributeError: attribute '__doc__' of 'type' objects is not writable.

于 2013-12-04T23:43:06.297 に答える
66

同じことを疑問に思っているときに、Google経由でこの古い質問に出くわしました。

クラス宣言から直接 namedtuple() を呼び出すことで、さらに整理できることを指摘したかっただけです。

from collections import namedtuple

class Point(namedtuple('Point', 'x y')):
    """Here is the docstring."""
于 2013-03-27T19:30:28.017 に答える
55

からの戻り値の周りに単純な空のラッパー クラスを作成することで、これを実現できますnamedtuple。私が作成したファイルの内容 ( nt.py):

from collections import namedtuple

Point_ = namedtuple("Point", ["x", "y"])

class Point(Point_):
    """ A point in 2d space """
    pass

次に、Python REPL で:

>>> print nt.Point.__doc__
 A point in 2d space 

または、次のようにすることもできます。

>>> help(nt.Point)  # which outputs...
モジュール nt のクラス Point に関するヘルプ:

クラス Point(ポイント)
 | | 2次元空間の点
 | |  
 | | メソッド解決順序:
 | | 点
 | | 点
 | | __builtin__.tuple
 | | __ビルトイン__.オブジェクト
 ...

毎回手作業でそれを行うのが好きでない場合は、これを行うための一種のファクトリ関数を書くのは簡単です:

def NamedTupleWithDocstring(docstring, *ntargs):
    nt = namedtuple(*ntargs)
    class NT(nt):
        __doc__ = docstring
    return NT

Point3D = NamedTupleWithDocstring("A point in 3d space", "Point3d", ["x", "y", "z"])

p3 = Point3D(1,2,3)

print p3.__doc__

出力:

A point in 3d space
于 2009-10-22T11:03:35.707 に答える
40

簡単な方法でドキュメント文字列を名前付きタプルに追加することは可能ですか?

はい、いくつかの点で。

サブクラスの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__も参照してください。

于 2015-02-17T18:19:22.063 に答える
7

Python 3.5 以降、オブジェクトの docstring をnamedtuple更新できます。

whatsnewから:

Point = namedtuple('Point', ['x', 'y'])
Point.__doc__ += ': Cartesian coodinate'
Point.x.__doc__ = 'abscissa'
Point.y.__doc__ = 'ordinate'
于 2016-09-04T19:20:42.343 に答える
3

受け入れられた回答で提案されているように、ラッパー クラスを使用する必要はありません。文字通り、docstringを追加するだけです。

from collections import namedtuple

Point = namedtuple("Point", ["x", "y"])
Point.__doc__="A point in 2D space"

( を使用した例ipython3):

In [1]: Point?
Type:       type
String Form:<class '__main__.Point'>
Docstring:  A point in 2D space

In [2]: 

ほら!

于 2014-09-24T12:48:47.200 に答える
1

Raymond Hettinger による独自のバージョンのnamedtuple ファクトリ関数を作成し、オプションのdocstring引数を追加することができます。ただし、レシピと同じ基本的な手法を使用して独自のファクトリ関数を定義する方が簡単で、間違いなく優れています。いずれにせよ、再利用可能なものになります。

from collections import namedtuple

def my_namedtuple(typename, field_names, verbose=False,
                 rename=False, docstring=''):
    '''Returns a new subclass of namedtuple with the supplied
       docstring appended to the default one.

    >>> Point = my_namedtuple('Point', 'x, y', docstring='A point in 2D space')
    >>> print Point.__doc__
    Point(x, y):  A point in 2D space
    '''
    # create a base class and concatenate its docstring and the one passed
    _base = namedtuple(typename, field_names, verbose, rename)
    _docstring = ''.join([_base.__doc__, ':  ', docstring])

    # fill in template to create a no-op subclass with the combined docstring
    template = '''class subclass(_base):
        %(_docstring)r
        pass\n''' % locals()

    # execute code string in a temporary namespace
    namespace = dict(_base=_base, _docstring=_docstring)
    try:
        exec template in namespace
    except SyntaxError, e:
        raise SyntaxError(e.message + ':\n' + template)

    return namespace['subclass']  # subclass object created
于 2010-07-28T04:23:11.637 に答える
-2

いいえ、モジュール、クラス、および関数 (メソッドを含む) にのみドキュメント文字列を追加できます

于 2009-10-22T10:58:34.143 に答える