Dodawanie docstrings do namedtuples?
Czy można w prosty sposób dodać ciąg dokumentacji do nazwaple?
Próbowałem
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)"
Ale to nie wystarczy. Czy można to zrobić w inny sposób? 9 answers
Możesz to osiągnąć, tworząc prostą, pustą klasę owijającą wokół zwracanej wartości z namedtuple
. Zawartość pliku, który utworzyłem (nt.py
):
from collections import namedtuple
Point_ = namedtuple("Point", ["x", "y"])
class Point(Point_):
""" A point in 2d space """
pass
Następnie w Pythonie REPL:
>>> print nt.Point.__doc__
A point in 2d space
Lub możesz zrobić:
>>> 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 ...
Jeśli nie lubisz robić tego ręcznie za każdym razem, jest trywialne napisać coś w rodzaju funkcji fabrycznej, aby to zrobić:
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__
Które wyjście:
A point in 3d space
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-30 23:24:57
Natknąłem się na to stare pytanie przez Google, zastanawiając się nad tym samym.
Chciałem tylko zaznaczyć, że możesz to jeszcze bardziej uporządkować, wywołując namedtuple () bezpośrednio z deklaracji klasy:
from collections import namedtuple
class Point(namedtuple('Point', 'x y')):
"""Here is the docstring."""
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-30 23:23:38
W Pythonie 3 nie jest potrzebne żadne opakowanie, ponieważ atrybuty typów są zapisywalne.
from collections import namedtuple
Point = namedtuple('Point', 'x y')
Point.__doc__ = '''\
A 2-dimensional coordinate
x - the abscissa
y - the ordinate'''
To ściśle odpowiada standardowej definicji klasy, gdzie docstring podąża za nagłówkiem.
class Point():
'''A 2-dimensional coordinate
x - the abscissa
y - the ordinate'''
<class code>
To nie działa w Pythonie 2.
AttributeError: attribute '__doc__' of 'type' objects is not writable
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-04 23:43:06
Czy można w prosty sposób dodać ciąg dokumentacji do namedtuple?
Python 3
W Pythonie 3 możesz łatwo zmienić dokument na swojej nazwie:
NT = collections.namedtuple('NT', 'foo bar')
NT.__doc__ = """:param str foo: foo name
:param list bar: List of bars to bar"""
Który pozwala nam zobaczyć intencje dla nich, gdy wzywamy pomoc na nich:
Help on class NT in module __main__:
class NT(builtins.tuple)
| :param str foo: foo name
| :param list bar: List of bars to bar
...
Jest to naprawdę proste w porównaniu z trudnościami, jakie mamy, aby osiągnąć to samo w Pythonie 2.
Python 2
W Pythonie 2, będziesz potrzebował do
- podklasa nazwa_tuple i
- declare
__slots__ == ()
Deklarowanie __slots__
jest ważną częścią, której brakuje innym odpowiedziom .
Jeśli nie zadeklarujesz __slots__
- możesz dodać zmienne atrybuty ad-hoc do instancji, wprowadzając błędy.
class Foo(namedtuple('Foo', 'bar')):
"""no __slots__ = ()!!!"""
A teraz:
>>> f = Foo('bar')
>>> f.bar
'bar'
>>> f.baz = 'what?'
>>> f.__dict__
{'baz': 'what?'}
Każda instancja utworzy oddzielny __dict__
, gdy dostęp do __dict__
jest dostępny (brak __slots__
w inny sposób nie utrudni funkcjonalności, ale lekkość krotki, niezmienność i deklarowane atrybuty są ważnymi cechami nazw krotek).
Będziesz również chciał __repr__
, jeśli chcesz, aby to, co jest wyświetlane w wierszu poleceń, dało ci równoważny obiekt:
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__ = ()
A __repr__
Jak to jest potrzebne, jeśli utworzysz bazę nazwytuple z inną nazwą (tak jak zrobiliśmy powyżej z argumentem name string, 'NTBase'
):
def __repr__(self):
return 'NT(foo={0}, bar={1})'.format(
repr(self.foo), repr(self.bar))
Aby przetestować repr, instantiate, następnie test na równość przejścia do eval(repr(instance))
nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt
Przykład z dokumentacji
Docs również daje taki przykład, dotyczący __slots__
- dodaję do niego swój własny 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)
...
Podklasa pokazana powyżej ustawia
__slots__
na pustą krotkę. To pomaga utrzymuj niskie wymagania dotyczące pamięci, zapobiegając tworzeniu instancji słowniki.
To pokazuje użycie in-place( jak sugeruje inna odpowiedź tutaj), ale zauważ, że in-place użycie może stać się mylące, gdy patrzysz na kolejność rozdzielczości metody, jeśli debugujesz, dlatego pierwotnie zasugerowałem użycie Base
jako sufiksu dla bazy nazwastuple:
>>> Point.mro()
[<class '__main__.Point'>, <class '__main__.Point'>, <type 'tuple'>, <type 'object'>]
# ^^^^^---------------------^^^^^-- same names!
Aby zapobiec tworzeniu __dict__
podczas podklasowania z klasy, która go używa, musisz również zadeklarować ją w podklasie. Zobacz również ta odpowiedź, aby uzyskać więcej zastrzeżeń dotyczących używania __slots__
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-28 02:46:09
Od wersji Pythona 3.5 docstringi dla obiektów namedtuple
mogą być aktualizowane.
From the whatsnew :
Point = namedtuple('Point', ['x', 'y']) Point.__doc__ += ': Cartesian coodinate' Point.x.__doc__ = 'abscissa' Point.y.__doc__ = 'ordinate'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-26 18:49:56
Nie ma potrzeby używania klasy wrapper, zgodnie z sugestią zaakceptowanej odpowiedzi. Po prostu dosłownie dodaj a docstring:
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
Point.__doc__="A point in 2D space"
Daje to: (przykład użycia ipython3
):
In [1]: Point?
Type: type
String Form:<class '__main__.Point'>
Docstring: A point in 2D space
In [2]:
voila!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-24 12:48:47
Możesz wymyślić własną wersję namedtuple Factory function by Raymond Hettinger and add an optional docstring
argument. Jednak byłoby łatwiej-i prawdopodobnie lepiej-po prostu zdefiniować własną funkcję fabryczną przy użyciu tej samej podstawowej techniki, jak w przepisie. Tak czy inaczej, skończysz z czymś wielokrotnego użytku.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-30 23:26:38
W Pythonie 3.6+ możesz użyć:
class Point(NamedTuple):
"""
A point in 2D space
"""
x: float
y: float
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-07 13:40:12
Nie, można dodawać tylko ciągi dokumentów do modułów, klas i funkcji (w tym metod)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-22 10:58:34