代码之家  ›  专栏  ›  技术社区  ›  Rickard

是否将docstrings添加到namedtuples?

  •  69
  • Rickard  · 技术社区  · 16 年前

    是否可以轻松地将文档字符串添加到名称副本?

    我试过

    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)"
    

    但这并不能解决问题。有没有可能用其他方法?

    10 回复  |  直到 7 年前
        1
  •  43
  •   Aaron Hall    10 年前

    您可以通过在返回值周围创建一个简单的空包装类来实现这一点。 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...
    
    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__
    

    输出:

    A point in 3d space
    
        2
  •  57
  •   Terry Jan Reedy    12 年前

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

    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>
    

    这在Python2中不起作用。

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

        3
  •  57
  •   Aaron Hall    10 年前

    通过谷歌发现了这个老问题,同时也在想同样的事情。

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

    from collections import namedtuple
    
    class Point(namedtuple('Point', 'x y')):
        """Here is the docstring."""
    
        4
  •  25
  •   Aaron Hall    9 年前

    是否可以轻松地将文档字符串添加到名称副本?

    Python 3

    在python 3中,您可以很容易地更改名称为duple的文档:

    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
    ...
    

    与我们在Python2中完成相同任务所遇到的困难相比,这是非常直接的。

    Python 2

    在Python2中,您需要

    • 将名称分为两个子类,以及
    • 声明 __slots__ == ()

    宣告 __slots__ 其他人回答的一个重要问题 .

    如果你不申报 _插槽__ -您可以向实例添加可变的特别属性,从而引入错误。

    class Foo(namedtuple('Foo', 'bar')):
        """no __slots__ = ()!!!"""
    

    现在:

    >>> f = Foo('bar')
    >>> f.bar
    'bar'
    >>> f.baz = 'what?'
    >>> f.__dict__
    {'baz': 'what?'}
    

    每个实例将创建一个单独的 __dict__ 什么时候 第二节 被访问(缺少 斯洛茨基 否则不会妨碍功能,但元组的轻量级、不可变性和声明的属性都是NamedDuples的重要特性)。

    你还需要一个 __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__ = ()
    

    第二乐章 如果用不同的名称创建基名称duple(就像上面对name-string参数所做的那样, '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
    

    文档中的示例

    这个 docs also 举这样一个例子,关于 斯洛茨基 -我正在添加自己的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)
    

    上面显示的子类集合 斯洛茨基 到一个空元组。这有助于 通过阻止创建实例来降低内存需求 字典。

    这演示了就地使用(正如这里的另一个答案所建议的那样),但是请注意,如果正在调试,当您查看方法解析顺序时,就地使用可能会变得混乱,这就是我最初建议使用的原因 Base 作为基名称的后缀duple:

    >>> Point.mro()
    [<class '__main__.Point'>, <class '__main__.Point'>, <type 'tuple'>, <type 'object'>]
                    # ^^^^^---------------------^^^^^-- same names!        
    

    防止创建 第二节 当从使用它的类中进行子类化时,还必须在子类中声明它。也见 this answer for more caveats on using __slots__ .

        5
  •  6
  •   vishes_shell hendrixski    9 年前

    从python 3.5开始, namedtuple 对象可以更新。

    whatsnew :

    Point = namedtuple('Point', ['x', 'y'])
    Point.__doc__ += ': Cartesian coodinate'
    Point.x.__doc__ = 'abscissa'
    Point.y.__doc__ = 'ordinate'
    
        6
  •  4
  •   Docent    8 年前

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

    class Point(NamedTuple):
        """
        A point in 2D space
        """
        x: float
        y: float
    
        7
  •  3
  •   A Sz    11 年前

    不需要使用被接受的答案所建议的包装类。简单地说就是 添加 文档字符串:

    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]: 
    

    Voice!

        8
  •  1
  •   Aaron Hall    10 年前

    你可以编造你自己的版本 namedtuple factory function 由Raymond Hettinger提供,并添加一个可选的 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
    
        9
  •  0
  •   Steven    7 年前

    我创建了这个函数来快速创建一个命名的tuple,并记录tuple及其每个参数:

    from collections import namedtuple
    
    
    def named_tuple(name, description='', **kwargs):
        """
        A named tuple with docstring documentation of each of its parameters
        :param str name: The named tuple's name
        :param str description: The named tuple's description
        :param kwargs: This named tuple's parameters' data with two different ways to describe said parameters. Format:
            <pre>{
                str: ( # The parameter's name
                    str, # The parameter's type
                    str # The parameter's description
                ),
                str: str, # The parameter's name: the parameter's description
                ... # Any other parameters
            }</pre>
        :return: collections.namedtuple
        """
        parameter_names = list(kwargs.keys())
    
        result = namedtuple(name, ' '.join(parameter_names))
    
        # If there are any parameters provided (such that this is not an empty named tuple)
        if len(parameter_names):
            # Add line spacing before describing this named tuple's parameters
            if description is not '':
                description += "\n"
    
            # Go through each parameter provided and add it to the named tuple's docstring description
            for parameter_name in parameter_names:
                parameter_data = kwargs[parameter_name]
    
                # Determine whether parameter type is included along with the description or
                # if only a description was provided
                parameter_type = ''
                if isinstance(parameter_data, str):
                    parameter_description = parameter_data
                else:
                    parameter_type, parameter_description = parameter_data
    
                description += "\n:param {type}{name}: {description}".format(
                    type=parameter_type + ' ' if parameter_type else '',
                    name=parameter_name,
                    description=parameter_description
                )
    
                # Change the docstring specific to this parameter
                getattr(result, parameter_name).__doc__ = parameter_description
    
        # Set the docstring description for the resulting named tuple
        result.__doc__ = description
    
        return result
    

    然后可以创建一个新的命名元组:

    MyTuple = named_tuple(
        "MyTuple",
        "My named tuple for x,y coordinates",
        x="The x value",
        y="The y value"
    )
    

    然后用您自己的数据实例化所描述的命名元组,即。

    t = MyTuple(4, 8)
    print(t) # prints: MyTuple(x=4, y=8)
    

    执行时 help(MyTuple) 通过python3命令行显示以下内容:

    Help on class MyTuple:
    
    class MyTuple(builtins.tuple)
     |  MyTuple(x, y)
     |
     |  My named tuple for x,y coordinates
     |
     |  :param x: The x value
     |  :param y: The y value
     |
     |  Method resolution order:
     |      MyTuple
     |      builtins.tuple
     |      builtins.object
     |
     |  Methods defined here:
     |
     |  __getnewargs__(self)
     |      Return self as a plain tuple.  Used by copy and pickle.
     |
     |  __repr__(self)
     |      Return a nicely formatted representation string
     |
     |  _asdict(self)
     |      Return a new OrderedDict which maps field names to their values.
     |
     |  _replace(_self, **kwds)
     |      Return a new MyTuple object replacing specified fields with new values
     |
     |  ----------------------------------------------------------------------
     |  Class methods defined here:
     |
     |  _make(iterable) from builtins.type
     |      Make a new MyTuple object from a sequence or iterable
     |
     |  ----------------------------------------------------------------------
     |  Static methods defined here:
     |
     |  __new__(_cls, x, y)
     |      Create new instance of MyTuple(x, y)
     |
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |
     |  x
     |      The x value
     |
     |  y
     |      The y value
     |
     |  ----------------------------------------------------------------------
     |  Data and other attributes defined here:
     |  
     |  _fields = ('x', 'y')
     |  
     |  _fields_defaults = {}
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from builtins.tuple:
     |  
     |  __add__(self, value, /)
     |      Return self+value.
     |  
     |  __contains__(self, key, /)
     |      Return key in self.
     |  
     |  __eq__(self, value, /)
     |      Return self==value.
     |  
     |  __ge__(self, value, /)
     |      Return self>=value.
     |  
     |  __getattribute__(self, name, /)
     |      Return getattr(self, name).
     |  
     |  __getitem__(self, key, /)
     |      Return self[key].
     |  
     |  __gt__(self, value, /)
     |      Return self>value.
     |  
     |  __hash__(self, /)
     |      Return hash(self).
     |  
     |  __iter__(self, /)
     |      Implement iter(self).
     |  
     |  __le__(self, value, /)
     |      Return self<=value.
     |  
     |  __len__(self, /)
     |      Return len(self).
     |  
     |  __lt__(self, value, /)
     |      Return self<value.
     |  
     |  __mul__(self, value, /)
     |      Return self*value.
     |  
     |  __ne__(self, value, /)
     |      Return self!=value.
     |  
     |  __rmul__(self, value, /)
     |      Return value*self.
     |  
     |  count(self, value, /)
     |      Return number of occurrences of value.
     |  
     |  index(self, value, start=0, stop=9223372036854775807, /)
     |      Return first index of value.
     |      
     |      Raises ValueError if the value is not present.
    

    或者,也可以通过以下方式指定参数的类型:

    MyTuple = named_tuple(
        "MyTuple",
        "My named tuple for x,y coordinates",
        x=("int", "The x value"),
        y=("int", "The y value")
    )
    
        10
  •  -2
  •   Jeffrey Aylesworth    16 年前

    不可以,只能向模块、类和函数(包括方法)添加文档字符串

    推荐文章