Wie dokumentiere ich Klassenattribute in Python? [geschlossen]

113

Ich schreibe eine Lightweight-Klasse, deren Attribute öffentlich zugänglich sein sollen und nur manchmal in bestimmten Instanziierungen überschrieben werden. In der Python-Sprache gibt es keine Möglichkeit, Dokumentzeichenfolgen für Klassenattribute oder andere Attribute zu erstellen. Was ist der erwartete und unterstützte Weg, um diese Attribute zu dokumentieren? Momentan mache ich so etwas:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
    """

    flight_speed = 691
    __doc__ += """
        flight_speed (691)
          The maximum speed that such a bird can attain.
    """

    nesting_grounds = "Raymond Luxury-Yacht"
    __doc__ += """
        nesting_grounds ("Raymond Luxury-Yacht")
          The locale where these birds congregate to reproduce.
    """

    def __init__(self, **keyargs):
        """Initialize the Albatross from the keyword arguments."""
        self.__dict__.update(keyargs)

Dies führt dazu, dass der Docstring der Klasse den anfänglichen Standard-Docstring-Abschnitt sowie die Zeilen enthält, die für jedes Attribut über eine erweiterte Zuordnung zu hinzugefügt wurden __doc__.

Obwohl dieser Stil in der EU nicht ausdrücklich verboten zu sein scheint Richtlinien für Docstring-Stile , wird er auch nicht als Option erwähnt. Der Vorteil hierbei ist, dass es eine Möglichkeit bietet, Attribute neben ihren Definitionen zu dokumentieren, während gleichzeitig eine vorzeigbare Klassen-Dokumentzeichenfolge erstellt wird, und dass keine Kommentare geschrieben werden müssen, die die Informationen aus der Dokumentzeichenfolge wiederholen. Ich bin immer noch etwas verärgert, dass ich die Attribute tatsächlich zweimal schreiben muss; Ich denke darüber nach, die Zeichenfolgendarstellungen der Werte in der Dokumentzeichenfolge zu verwenden, um zumindest eine Verdoppelung der Standardwerte zu vermeiden.

Ist dies ein abscheulicher Verstoß gegen die Ad-hoc-Community-Konventionen? Ist es okay? Gibt es einen besseren Weg? Beispielsweise ist es möglich, ein Wörterbuch mit Werten und Dokumentzeichenfolgen für die Attribute zu erstellen und den Inhalt __dict__gegen Ende der Klassendeklaration der Klasse und der Dokumentzeichenfolge hinzuzufügen . Dies würde die Notwendigkeit verringern, die Attributnamen und -werte zweimal einzugeben. edit : Diese letzte Idee ist meiner Meinung nach nicht wirklich möglich, zumindest nicht ohne das dynamische Erstellen der gesamten Klasse aus Daten, was eine wirklich schlechte Idee zu sein scheint, es sei denn, es gibt einen anderen Grund dafür.

Ich bin ziemlich neu in Python und arbeite immer noch an den Details des Codierungsstils, daher sind auch nicht verwandte Kritiken willkommen.

intuitiv
quelle
Wenn Sie nach einer Möglichkeit suchen, Django-Modellattribute zu dokumentieren, kann dies hilfreich sein: djangosnippets.org/snippets/2533
Michael Scheper
3
Duplikat von Wie werden Felder und Eigenschaften in Python dokumentiert? die eine andere Lösung halten.
bufh
1
Ich verstehe nicht, warum dies meinungsbasiert ist. Python dokumentiert speziell die akzeptablen Konventionen in PEPs. Es gibt verschiedene Python-Quellwerkzeuge, die ordnungsgemäß formatierte Dokumentation extrahieren. Tatsächlich hat Python attribute doc stringin PEP 257 eine Erwähnung , die nicht gut bekannt ist und schwer zu finden scheint, um die Frage des OP zu beantworten, und die von einigen Quellwerkzeugen unterstützt wird. Dies ist keine Meinung. Es ist eine Tatsache und ein Teil der Sprache und ziemlich genau das, was das OP will.
NeilG

Antworten:

82

Um Verwirrung zu vermeiden: Der Begriff Eigenschaft hat in Python eine bestimmte Bedeutung . Sie sprechen von Klassenattributen . Da sie immer durch ihre Klasse behandelt werden, finde ich es sinnvoll, sie in der Dokumentzeichenfolge der Klasse zu dokumentieren. Etwas wie das:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
        flight_speed     The maximum speed that such a bird can attain.
        nesting_grounds  The locale where these birds congregate to reproduce.
    """
    flight_speed = 691
    nesting_grounds = "Throatwarbler Man Grove"

Ich denke, das ist viel einfacher für die Augen als der Ansatz in Ihrem Beispiel. Wenn ich wirklich wollte, dass eine Kopie der Attributwerte in der Dokumentzeichenfolge angezeigt wird, würde ich sie neben oder unter die Beschreibung jedes Attributs setzen.

Beachten Sie, dass in Python Dokumentzeichenfolgen tatsächliche Elemente der von ihnen dokumentierten Objekte sind und nicht nur Anmerkungen zum Quellcode. Da Klassenattributvariablen keine Objekte selbst sind, sondern Verweise auf Objekte, können sie keine eigenen Dokumentzeichenfolgen enthalten. Ich denke, Sie könnten sich für Dokumentzeichenfolgen in Referenzen einsetzen, um vielleicht zu beschreiben, "was hier hingehen soll" anstatt "was eigentlich hier ist", aber ich finde es einfach genug, dies in der Dokumentzeichenfolge der enthaltenen Klasse zu tun.

ʇSәɹoɈ
quelle
Ich denke, in den meisten Fällen ist dies in Ordnung, da die Attribute - danke für die Terminologiekorrektur - prägnant genug deklariert sind, dass sie nur zu Beginn der Klassendeklaration gruppiert werden können, ohne dass es unpraktisch ist, hin und her zu wechseln, um beide zu lesen die Dokumentation und den Standardwert} oder {beide Instanzen der Dokumentation und / oder den Standardwert aktualisieren}.
Intuitiert
1
Beachten Sie auch, dass in meinem Beispiel die Dokumentation für die Attribute in der Dokumentzeichenfolge der Klasse angezeigt wird. Eigentlich würde ich es vorziehen, die Dokumentation in Dokumentzeichenfolgen der Attribute selbst zu platzieren, aber dies funktioniert bei den meisten integrierten Typen nicht.
Intuitiert
Ja, meine ursprüngliche Idee war es, einfach z flight_speed = 691; flight_speed.__doc__ = "blah blah". Ich denke, das ist es, was Sie in Ihrer Bearbeitung erwähnen . Leider funktioniert dies nicht für Instanziierungen von (den meisten?) Eingebauten Typen (wie intin diesem Beispiel). Es funktioniert für Instanziierungen von benutzerdefinierten Typen. =========== Es gab tatsächlich einen PEP (Entschuldigung, vergessen Sie die Nummer), der das Hinzufügen von Dokumentzeichenfolgen für Klassen- / Modulattribute vorschlug, der jedoch abgelehnt wurde, weil sie keinen Weg fanden, dies klar zu machen ob die Dokumentzeichenfolgen für die vorhergehenden oder folgenden Attribute waren.
Intuitiert
2
Was ist, wenn es sich um Instanzattribute handelt? noch in der Klasse docstring dokumentieren oder was?
n611x007
1
@intuited War es dieser PEP? legacy.python.org/dev/peps/pep-0224
taz
30

Sie zitieren die PEP257: Docstring Konventionen im Abschnitt Was für ein docstring ist es heißt:

String-Literale, die an anderer Stelle im Python-Code vorkommen, können auch als Dokumentation dienen. Sie werden vom Python-Bytecode-Compiler nicht erkannt und sind nicht als Laufzeitobjektattribute zugänglich (dh nicht __doc__ zugewiesen). Zwei Arten von zusätzlichen Dokumentzeichenfolgen können jedoch von Softwaretools extrahiert werden:

Zeichenfolgenliterale, die unmittelbar nach einer einfachen Zuweisung auf der obersten Ebene eines Moduls, einer Klasse oder einer __init__ -Methode auftreten, werden als "Attribut-Dokumentzeichenfolgen" bezeichnet.

Dies wird in PEP 258: Attribute docstrings näher erläutert. Wie oben erklärt ʇsәɹoɈ. Ein Attribut ist kein Objekt, das ein __doc__ besitzen kann, daher werden sie nicht in help()oder pydoc angezeigt . Diese Dokumentzeichenfolgen können nur für die generierte Dokumentation verwendet werden.

Sie werden in Sphinx mit der Direktive autoattribute verwendet

Sphinx kann Kommentare in einer Zeile vor einer Zuweisung oder einen speziellen Kommentar nach einer Zuweisung oder eine Dokumentzeichenfolge nach der Definition verwenden, die automatisch dokumentiert wird.

marcz
quelle
1
jedi-vim Plugin erkennt auch Attribut-Docstrings.
Long Vu
1
Ich weiß nicht, wann dies eingeführt wurde, aber Sphinx 1.2.2 scheint Attribut-Docstrings in die generierte Dokumentation aufzunehmen.
Jochen
1
Danke @jochen, ich aktualisiere meine Antwort.
Marcz
3
Bitte beachten Sie, dass PEP 258 abgelehnt wird. In der Ablehnungserklärung heißt es: "Dies kann zwar als interessantes Designdokument für die jetzt unabhängigen Dokumente dienen, ist jedoch nicht mehr für die Aufnahme in die Standardbibliothek vorgesehen."
Michał Łazowik
13

Sie könnten Eigenschaften zu diesem Zweck missbrauchen. Eigenschaften enthalten einen Getter, einen Setter, einen Deleter und einen Docstring . Naiv würde dies sehr ausführlich werden:

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """Docstring goes here."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Dann haben Sie eine Dokumentzeichenfolge, die zu Cx gehört:

In [24]: print(C.x.__doc__)
Docstring goes here.

Dies für viele Attribute zu tun ist umständlich, aber Sie könnten sich eine Hilfsfunktion vorstellen, myprop:

def myprop(x, doc):
    def getx(self):
        return getattr(self, '_' + x)

    def setx(self, val):
        setattr(self, '_' + x, val)

    def delx(self):
        delattr(self, '_' + x)

    return property(getx, setx, delx, doc)

class C:
    a = myprop("a", "Hi, I'm A!")
    b = myprop("b", "Hi, I'm B!")

In [44]: c = C()

In [46]: c.b = 42

In [47]: c.b
Out[47]: 42

In [49]: print(C.b.__doc__)
Hi, I'm B!

Wenn Sie dann Pythons interaktiv aufrufen help, erhalten Sie:

Help on class C in module __main__:

class C
 |  Data descriptors defined here:
 |  
 |  a
 |      Hi, I'm A!
 |  
 |  b
 |      Hi, I'm B!

was ich denke, sollte so ziemlich das sein, wonach du suchst.

Edit : Mir ist jetzt klar, dass wir vielleicht vermeiden können, das erste Argument mypropüberhaupt weitergeben zu müssen, weil der interne Name keine Rolle spielt. Wenn nachfolgende Aufrufe von mypropirgendwie miteinander kommunizieren können, könnte es automatisch über einen langen und unwahrscheinlichen internen Attributnamen entscheiden. Ich bin mir sicher, dass es Möglichkeiten gibt, dies umzusetzen, aber ich bin mir nicht sicher, ob sie es wert sind.

gerrit
quelle