将docstrings添加到namedtuples?

Ric*_*ard 76 python docstring namedtuple

是否可以以简单的方式将文档字符串添加到namedtuple?

我试过了

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)"
Run Code Online (Sandbox Code Playgroud)

但这并没有削减它.是否有可能以其他方式做?

小智 62

通过谷歌遇到这个老问题,同时想知道同样的事情.

只是想指出你可以通过从类声明中调用namedtuple()来进一步整理它:

from collections import namedtuple

class Point(namedtuple('Point', 'x y')):
    """Here is the docstring."""
Run Code Online (Sandbox Code Playgroud)

  • 重要的是你在类中包含`__slots__ =()`.否则你会为你的attrs创建一个`__dict__`,失去了namedtuple的轻量级特性. (7认同)

Ter*_*edy 62

在Python 3中,不需要包装器,因为__doc__类型的属性是可写的.

from collections import namedtuple

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

x - the abscissa
y - the ordinate'''
Run Code Online (Sandbox Code Playgroud)

这与标准类定义密切对应,其中docstring遵循标题.

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

    x - the abscissa
    y - the ordinate'''
    <class code>
Run Code Online (Sandbox Code Playgroud)

这在Python 2中不起作用.

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


Mar*_*off 49

您可以通过围绕返回值创建一个简单的空包装类来实现此目的namedtuple.我创建的文件的内容(nt.py):

from collections import namedtuple

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

class Point(Point_):
    """ A point in 2d space """
    pass
Run Code Online (Sandbox Code Playgroud)

然后在Python REPL中:

>>> print nt.Point.__doc__
 A point in 2d space 
Run Code Online (Sandbox Code Playgroud)

或者你可以这样做:

>>> help(nt.Point)  # which outputs...
Run Code Online (Sandbox Code Playgroud)
Help on class Point in module nt:

class Point(Point)
 |  A point in 2d space
 |  
 |  Method resolution order:
 |      Point
 |      Point
 |      __builtin__.tuple
 |      __builtin__.object
 ...

如果您不喜欢每次都手动执行此操作,那么编写一个类型的工厂函数来执行此操作是微不足道的:

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__
Run Code Online (Sandbox Code Playgroud)

哪个输出:

A point in 3d space
Run Code Online (Sandbox Code Playgroud)

  • 如果将`__slots__ =()`添加到派生的子类中,则可以保留使用`namedtuple`的内存和性能优势 (4认同)
  • 子类化不会将`namedtuple`转换为成熟的“对象”吗?从而损失了命名元组的一些性能提升? (2认同)

Aar*_*all 27

是否可以以简单的方式将文档字符串添加到namedtuple?

Python 3

在Python 3中,您可以轻松更改namedtuple上的doc:

from typing import NamedTuple

class Card(NamedTuple):
    """This is a card type."""
    suit: str
    rank: str
Run Code Online (Sandbox Code Playgroud)

这使我们可以在调用帮助时查看它们的意图:

NT = collections.namedtuple('NT', 'foo bar')

NT.__doc__ = """:param str foo: foo name
:param list bar: List of bars to bar"""
Run Code Online (Sandbox Code Playgroud)

与我们在Python 2中完成同样的事情相比,这非常简单.

Python 2

在Python 2中,您需要

  • 子类是namedtuple,和
  • 宣布 class

声明typing.NamedTuple其他答案错过的重要部分.

如果您没有声明__slots__- 您可以向实例添加可变的ad-hoc属性,从而引入错误.

Help on class NT in module __main__:

class NT(builtins.tuple)
 |  :param str foo: foo name
 |  :param list bar: List of bars to bar
...
Run Code Online (Sandbox Code Playgroud)

现在:

class Foo(namedtuple('Foo', 'bar')):
    """no __slots__ = ()!!!"""
Run Code Online (Sandbox Code Playgroud)

每个实例都会__slots____slots__ == ()访问时创建一个单独的(缺少__slots__不会妨碍功能,但元组的轻量级,不变性和声明的属性都是namedtuples的重要特性).

__slots__如果您希望在命令行上回显的内容为您提供等效对象,您还需要一个:

>>> f = Foo('bar')
>>> f.bar
'bar'
>>> f.baz = 'what?'
>>> f.__dict__
{'baz': 'what?'}
Run Code Online (Sandbox Code Playgroud)

__dict__,如果你创建一个不同的名称基本namedtuple(就像我们的名称字符串参数,上面不喜欢,这是需要__dict__):

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__ = ()
Run Code Online (Sandbox Code Playgroud)

要测试repr,实例化,然后测试传递的相等性 __slots__

    def __repr__(self):
        return 'NT(foo={0}, bar={1})'.format(
                repr(self.foo), repr(self.bar))
Run Code Online (Sandbox Code Playgroud)

文档中的示例

文档还给出这样一个例子,关于__repr__-我加入我自己的文档字符串给它:

nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt
Run Code Online (Sandbox Code Playgroud)

...

上面显示的子类设置__repr__为空元组.这有助于防止创建实例字典,从而降低内存需求.

这演示了就地使用(如此处建议的另一个答案),但请注意,当您查看方法解析顺序时,就地使用可能会变得混乱,如果您正在调试,这就是我最初建议使用'NTBase'后缀的原因对于basetitle的基础:

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)
Run Code Online (Sandbox Code Playgroud)

要防止eval(repr(instance))从使用它的类创建子类时,还必须在子类中声明它.有关使用的更多警告,__slots__请参阅此答案.

  • 尽管不像其他答案那样简洁明了,但这应该是公认的答案,因为它突出了“__slots__”的重要性。没有它,您将失去命名元组的轻量级价值。 (4认同)

vis*_*ell 6

从Python 3.5开始,namedtuple可以更新对象的文档字符串.

whatsnew:

Point = namedtuple('Point', ['x', 'y'])
Point.__doc__ += ': Cartesian coodinate'
Point.x.__doc__ = 'abscissa'
Point.y.__doc__ = 'ordinate'
Run Code Online (Sandbox Code Playgroud)


Doc*_*ent 6

在 Python 3.6+ 中,您可以使用:

class Point(NamedTuple):
    """
    A point in 2D space
    """
    x: float
    y: float
Run Code Online (Sandbox Code Playgroud)