Ist es möglich, einem Namedtuple auf einfache Weise eine Dokumentationszeichenfolge hinzuzufügen?
Ja, in mehrfacher Hinsicht.
Typisierung der Unterklasse.NamedTuple - Python 3.6+
Ab Python 3.6 können wir eine class
Definition typing.NamedTuple
direkt mit einer Dokumentzeichenfolge (und Anmerkungen!) Verwenden:
from typing import NamedTuple
class Card(NamedTuple):
"""This is a card type."""
suit: str
rank: str
Im Vergleich zu Python 2 __slots__
ist es nicht erforderlich , leer zu deklarieren . In Python 3.8 ist dies nicht einmal für Unterklassen erforderlich.
Beachten Sie, dass das Deklarieren __slots__
nicht leer sein darf!
In Python 3 können Sie das Dokument auch einfach in einem benannten Tupel ändern:
NT = collections.namedtuple('NT', 'foo bar')
NT.__doc__ = """:param str foo: foo name
:param list bar: List of bars to bar"""
So können wir die Absicht für sie sehen, wenn wir Hilfe bei ihnen anrufen:
Help on class NT in module __main__:
class NT(builtins.tuple)
| :param str foo: foo name
| :param list bar: List of bars to bar
...
Dies ist im Vergleich zu den Schwierigkeiten, die wir in Python 2 haben, sehr einfach.
Python 2
In Python 2 müssen Sie
- Unterklasse das benannte Tupel und
- erklären
__slots__ == ()
Die Erklärung __slots__
ist ein wichtiger Teil, den die anderen Antworten hier vermissen .
Wenn Sie nicht deklarieren, können __slots__
Sie den Instanzen veränderbare Ad-hoc-Attribute hinzufügen und Fehler einführen.
class Foo(namedtuple('Foo', 'bar')):
"""no __slots__ = ()!!!"""
Und nun:
>>> f = Foo('bar')
>>> f.bar
'bar'
>>> f.baz = 'what?'
>>> f.__dict__
{'baz': 'what?'}
Jede Instanz erstellt __dict__
beim __dict__
Zugriff eine separate Instanz (das Fehlen von __slots__
wird die Funktionalität sonst nicht beeinträchtigen, aber die Leichtigkeit des Tupels, die Unveränderlichkeit und die deklarierten Attribute sind wichtige Merkmale von Namedtuples).
Sie möchten auch ein __repr__
, wenn Sie möchten, dass das, was in der Befehlszeile wiedergegeben wird, ein gleichwertiges Objekt enthält:
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__ = ()
Ein __repr__
ähnliches wird benötigt, wenn Sie die Basis namenstupel mit einem anderen Namen erstellen (wie oben mit dem Argument name string 'NTBase'
):
def __repr__(self):
return 'NT(foo={0}, bar={1})'.format(
repr(self.foo), repr(self.bar))
Um den Repr zu testen, instanziieren Sie und testen Sie dann die Gleichheit eines Passes zu eval(repr(instance))
nt = NT('foo', 'bar')
assert eval(repr(nt)) == nt
Beispiel aus der Dokumentation
Die Dokumente geben auch ein solches Beispiel in Bezug auf __slots__
- ich füge meine eigene Dokumentzeichenfolge hinzu:
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)
...
Die oben gezeigte Unterklasse setzt __slots__
auf ein leeres Tupel. Dies hilft, den Speicherbedarf niedrig zu halten, indem die Erstellung von Instanzwörterbüchern verhindert wird.
Dies zeigt die direkte Verwendung (wie eine andere Antwort hier vorschlägt). Beachten Sie jedoch, dass die direkte Verwendung beim Debuggen verwirrend werden kann, wenn Sie sich die Reihenfolge der Methodenauflösung ansehen. Aus diesem Grund habe ich ursprünglich die Verwendung Base
als Suffix vorgeschlagen für die Basis namenstuple:
>>> Point.mro()
[<class '__main__.Point'>, <class '__main__.Point'>, <type 'tuple'>, <type 'object'>]
# ^^^^^---------------------^^^^^-- same names!
Um zu verhindern, dass eine __dict__
Unterklasse aus einer Klasse erstellt wird, die sie verwendet, müssen Sie sie auch in der Unterklasse deklarieren. Siehe auch diese Antwort für weitere Einschränkungen bei der Verwendung__slots__
.
namedtuple
in ein vollwertiges "Objekt" umwandeln ? Dabei einige der Leistungssteigerungen durch Named-Tupel verlieren?