98 votes

Ajouter des docstrings aux namedtuples ?

Est-il possible d'ajouter une chaîne de documentation à un namedtuple de manière simple ?

J'ai essayé

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

mais ça ne suffit pas. Est-il possible de procéder d'une autre manière ?

75voto

Terry Jan Reedy Points 441

En Python 3, aucun wrapper n'est nécessaire, car la fonction __doc__ les attributs des types sont inscriptibles.

from collections import namedtuple

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

x - the abscissa
y - the ordinate'''

Cela correspond étroitement à une définition de classe standard, où la docstring suit l'en-tête.

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

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

Cela ne fonctionne pas dans Python 2.

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

68voto

CoupleWavyLines Points 321

Je suis tombé sur cette vieille question via Google en me demandant la même chose.

Je voulais juste signaler que vous pouvez encore mieux faire le ménage en appelant namedtuple() dès la déclaration de la classe :

from collections import namedtuple

class Point(namedtuple('Point', 'x y')):
    """Here is the docstring."""

10 votes

Il est important que vous incluiez __slots__ = () dans la classe. Sinon, vous créez un __dict__ pour vos attrs, perdant ainsi la légèreté de namedtuple.

56voto

Mark Rushakoff Points 97350

Pour ce faire, il suffit de créer une classe d'enveloppe simple et vide autour de la valeur renvoyée par la fonction namedtuple . Contenu d'un fichier que j'ai créé ( nt.py ):

from collections import namedtuple

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

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

Puis dans le REPL de Python :

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

Ou vous pourriez le faire :

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

Si vous n'aimez pas faire cela à la main à chaque fois, il est trivial d'écrire une sorte de fonction d'usine pour le faire :

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__

qui sort :

A point in 3d space

2 votes

Le fait de sous-classer ne va-t-il pas convertir l'option namedtuple en un "objet" à part entière ? En perdant ainsi une partie des gains de performance des nuplets nommés ?

5 votes

Si vous ajoutez __slots__ = () à la sous-classe dérivée, vous pouvez conserver les avantages en termes de mémoire et de performances de l'utilisation de la fonction namedtuple

0 votes

Cela ajoute encore un niveau supplémentaire au MRO, ce qui n'est pas justifié pour une docstring. Cependant, on peut simplement assigner à __doc__ et avoir une docstring personnalisée enregistrée dans l'objet original.

1voto

martineau Points 21665

Vous pourriez concocter votre propre version du fonction de fabrique de tuples nommés de Raymond Hettinger et ajouter une option docstring argument.  Cependant, il serait plus facile - et sans doute meilleur - de définir votre propre fonction d'usine en utilisant la même technique de base que dans la recette.  Dans tous les cas, vous obtiendrez quelque chose de réutilisable.

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

-3voto

Jeffrey Aylesworth Points 2889

Non, vous pouvez uniquement ajouter des chaînes de documents aux modules, classes et fonctions (y compris les méthodes).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X