how create python docstring namedtuple

how to create namedtuple in python



¿Agregando docstrings a namedtuples? (9)

¿Es posible agregar una cadena de documentación a una tilde nombrada de una manera fácil?

Lo intenté

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

pero eso no lo corta. ¿Es posible hacerlo de alguna otra manera?


¿Es posible agregar una cadena de documentación a una tilde nombrada de una manera fácil?

Python 3

En Python 3, puede modificar fácilmente el documento en su ruta de nombre:

NT = collections.namedtuple(''NT'', ''foo bar'') NT.__doc__ = """:param str foo: foo name :param list bar: List of bars to bar"""

Lo que nos permite ver su intención cuando solicitamos ayuda sobre ellos:

Help on class NT in module __main__: class NT(builtins.tuple) | :param str foo: foo name | :param list bar: List of bars to bar ...

Esto es realmente sencillo en comparación con las dificultades que tenemos para lograr lo mismo en Python 2.

Python 2

En Python 2, necesitarás

  • subclase the namedtuple, y
  • declarar __slots__ == ()

Declarar __slots__ es una parte importante que las otras respuestas aquí se pierden .

Si no declara __slots__ , puede agregar atributos mutables ad-hoc a las instancias, introduciendo errores.

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

Y ahora:

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

Cada instancia creará un __dict__ separado cuando se acceda a __dict__ (la falta de __slots__ no impedirá la funcionalidad, pero la ligereza de la tupla, la inmutabilidad y los atributos declarados son todas características importantes de namedtuples).

También querrás un __repr__ , si quieres que se repita en la línea de comando para darte un objeto equivalente:

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__ = ()

un __repr__ como este es necesario si creas la base namedtuple con un nombre diferente (como hicimos anteriormente con el argumento string de nombre, ''NTBase'' ):

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

Para probar el repr, crea una instancia, luego prueba la igualdad de un pase a eval(repr(instance))

nt = NT(''foo'', ''bar'') assert eval(repr(nt)) == nt

Ejemplo de la documentación

Los documentos también dan un ejemplo, con respecto a __slots__ - Le agrego mi propia 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)

...

La subclase que se muestra arriba establece __slots__ a una tupla vacía. Esto ayuda a mantener bajos los requisitos de memoria al evitar la creación de diccionarios de instancia.

Esto demuestra el uso en el lugar (como sugiere otra respuesta aquí), pero tenga en cuenta que el uso in situ puede ser confuso cuando mira el orden de resolución del método, si está depurando, por lo que originalmente sugerí usar Base como sufijo para la base namedtuple:

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

Para evitar la creación de un __dict__ cuando se subclasifica de una clase que lo usa, también debe declararlo en la subclase. Consulte también esta respuesta para obtener más advertencias sobre el uso de __slots__ .


Desde Python 3.5, las cadenas de namedtuple para objetos namedtuple se pueden actualizar.

De lo whatsnew :

Point = namedtuple(''Point'', [''x'', ''y'']) Point.__doc__ += '': Cartesian coodinate'' Point.x.__doc__ = ''abscissa'' Point.y.__doc__ = ''ordinate''


En Python 3, no se necesita envoltorio, ya que los atributos de los tipos __doc__ se pueden escribir.

from collections import namedtuple Point = namedtuple(''Point'', ''x y'') Point.__doc__ = ''''''/ A 2-dimensional coordinate x - the abscissa y - the ordinate''''''

Esto se corresponde estrechamente con una definición de clase estándar, donde la docstring sigue al encabezado.

class Point(): ''''''A 2-dimensional coordinate x - the abscissa y - the ordinate'''''' <class code>

Esto no funciona en Python 2.

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


En Python 3.6+ puedes usar:

class Point(NamedTuple): """ A point in 2D space """ x: float y: float


No es necesario utilizar una clase contenedora tal como lo sugiere la respuesta aceptada. Simplemente agrega literalmente una docstring:

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

Esto da como resultado: (ejemplo usando ipython3 ):

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

Voilà!


No, solo puede agregar cadenas de documentos a módulos, clases y funciones (incluidos los métodos)


Puede inventar su propia versión de la función de fábrica de títulos nombrados por Raymond Hettinger y agregar un argumento de docstring opcional. Sin embargo, sería más fácil, y podría decirse mejor, definir su propia función de fábrica utilizando la misma técnica básica que en la receta. De cualquier manera, terminarás con algo reutilizable.

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


Puede lograrlo creando una clase contenedora simple y vacía alrededor del valor devuelto desde namedtuple . Contenido de un archivo que creé ( nt.py ):

from collections import namedtuple Point_ = namedtuple("Point", ["x", "y"]) class Point(Point_): """ A point in 2d space """ pass

Luego, en el REPL de Python:

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

O podrías hacer:

>>> 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 no le gusta hacerlo a mano cada vez, es trivial escribir una especie de función de fábrica para hacer esto:

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__

qué salidas:

A point in 3d space


Se encontró con esta vieja pregunta a través de Google mientras se preguntaba lo mismo.

Solo quería señalar que puede arreglarlo aún más llamando a namedtuple () desde la declaración de clase:

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