Python-Code dokumentieren

Bevor in diesem Artikel näher auf das Dokumentieren von Code eingegangen wird, zunächst ein paar Worte zu Kommentaren, um die es hier schwerpunktmäßig nicht geht. Kommentare, die mit dem #-Zeichen eingeleitet werden, sind eher kurze Ausführungen, die das “Wie” beschreiben. Sie sollen dabei helfen, den Code besser zu verstehen. Des Weiteren gibt es spezielle Kommentare, wie beispielsweise “ToDo” oder “FixMe”, die für den Entwickler eine Gedankenstütze darstellen.

Dagegen liegt beim Dokumentieren von Code das Hauptaugenmerk mehr darauf, die Nutzung und die Funktionalität deutlich zu machen.

Von Guido van Rossum, dem Erfinder von Python, stammt die Aussage:

“Code is more often read than written.”

Guido van Rossum

Dieser Satz verdeutlicht, weswegen es von Bedeutung ist, Code zu kommentieren und gegebenenfalls auch zu dokumentieren. Denn welcher Programmierer kennt nicht folgende Situation: Man öffnet ein Projekt, das man seit längerer Zeit nicht mehr angefaßt hat, und was muss man sich beim Lesen des Codes eingestehen? Das man nicht mehr nachvollziehen kann, was man gemacht hat. Was bedeutet noch gleich jene Zeile Code, oder welche Aufgabe erfüllt jene Funktion? In diesem Augenblick ist man froh über Kommentare oder eine erklärende Dokumentation.

Docstrings

In Python werden für die Dokumentation Docstrings (documentation strings) genutzt. Anhand der built-in Funktion help() kann man sich ein Bild davon machen. Denn die Eingabe von

>>> help(int)  

führt zur Ausgabe folgender Ausführungen:

Help on class int in module builtins:

class int(object)
 |  int([x]) -> integer
 |  int(x, base=10) -> integer
 |  
 |  Convert a number or string to an integer, or return 0 if no arguments
 |  are given.  If x is a number, return x.__int__().  For floating point
 |  numbers, this truncates towards zero.

[…]

Diese Hilfe wird durch Docstrings realisiert. Und so nützlich wie sie — wie hier — für die Klasse int sind, können sie auch für eigene Projekte sein.

Aber wie fügt man nun Docstrings zu seinen eigenen Projekten hinzu? Folgendes Beispiel soll dies verdeutlichen.

def add(number_one, number_two):
    return number_one + number_two

result = add(2, 100)
print(str(result))

Die Funktion ist sehr überschaubar: Zwei Zahlen, die an die Funktion add() übergeben werden, sollen addiert werden. Das Ergebnis wird anschließend in den Datentyp str konvertiert und ausgegeben.

Ein Docstring kann nun zur Funktion add() wie folgt hinzugefügt werden:

def add(number_one, number_two):
    """Addition of two numbers."""
    return number_one + number_two

Zusätzlich kann man noch die Argumente und den Rückgabewert erklären:

def add(number_one, number_two):
    """Addition of two numbers.

    Args:
        number_one (str): The first operand
        number_two (str): The second operand

    Returns:
        str: The result of the addition
    """

    return number_one + number_two

Praktisch ist, dass man anhand der Dokumentation sofort sehen kann, welche Datentypen gegeben sind. Gerade bei einer Programmiersprache, die nicht zwingend eine Type Annotation fordert, kann das sehr vorteilhaft sein. Für dieses Beispiel wird übrigens das Format Google Docstrings verwendet (siehe nächsten Abschnitt “Docstring-Formate”).

Es läßt sich trefflich darüber streiten, ob bei einer so einfachen Funktion das Hinzufügen eines Docstrings erforderlich ist. Denn wenn der Code derartig selbsterklärend ist, mag man dies als überflüssiges Beiwerk betrachten. Bei einfachen, kleineren Projekten bin auch ich nicht geneigt, eine Dokumentation anzulegen. Wenn ich aber Code dokumentiere, dann versuche ich dies konsequent umzusetzen, soll heißen, alle Elemente im Code werden dokumentiert.

Docstring-Formate

Es existieren unterschiedliche Formate. Nachfolgende Tabelle führt drei bekannte Docstring-Formate auf:

TypBeschreibung
NumPy/SciPyDas vom NumPy-Paket verwendete Format. Mehr Informationen gibt es hier.
Google DocstringsDie von Google empfohlene Formatierung. Weitere Informationen gibt es im entsprechenden Styleguide.
reStructuredTextDies ist die offizielle Python-Formatierung. Im Python Developer’s Guide gibt es mehr Infos hierzu.

Dokumentation in Visual Studio Code

Für gute Code-Editoren existieren Extensions, mit denen sich Docstrings erstellen lassen. Ihr solltet nachsehen, ob es für den Editor Eurer Wahl eine Extension gibt, die eine Auswahl hinsichtlich der Docstring-Formatierung zulässt. Im Falle von Visual Studio Code kann man zum Beispiel autoDocstring verwenden. Ein Docstring lässt sich dann mit cmd + shift + 2 (macOS) oder ctrl + shift + 2 (Windows) hinzufügen.

Nach der Installation von autoDocstring kann man in den Settings das gewünschte Format einstellen. Die Auswahl von “NumPy” würde beispielsweise zu folgendem Docstring führen:

def add(number_one, number_two):
    """[summary]

    :param number_one: [description]
    :type number_one: [type]
    :param number_two: [description]
    :type number_two: [type]
    :return: [description]
    :rtype: [type]
    """
    return number_one + number_two 

Dokumentation in PyCharm

Die beliebte Entwicklungsumgebung PyCharm nutzt standardmäßig reStructuredText. Ein Docstring wird durch die Eingabe von ”””, gefolgt von einer Bestätigung mit Enter, hinzugefügt. Bezogen auf die Funktion def add() sieht das dann so aus:

def add(number_one, number_two):
    """

    :param number_one: 
    :param number_two: 
    :return: 
    """
    return number_one + number_two

In den Einstellungen lässt sich dies unter

> Tools > Python Integrated Tools

ändern, also andere Formate auswählen.

Fazit

Spätestens wenn Ihr an größeren Projekten arbeitet, solltet Ihr Euch mit Docstrings auseinandersetzen. Und da Editoren und Entwicklungsumgebungen eine entsprechend Unterstützung für unterschiedliche Formate mitliefern, lassen sich Docstrings schnell zum Code hinzufügen. Setzt man sich zu einem späteren Zeitpunkt mit dem Projekt auseinander, ist man froh, wenn anhand von Kommentaren und Docstrings der Code nachvollzogen werden kann.

Abschließend möchte ich noch auf folgendes Hinweisen: Im obigen Beispiel wird eine if-Verzweigung in einer for-Schleife verwendet. In so einem Fall sollte man sich überlegen, ob eine List Comprehension sinnvoller ist. Zum einen kann es den Code lesbarer machen, zum anderen ist der Code effizienter. Dies würde hier dann wie folgt aussehen:

new_list = [int(number) * i for i in numbers if i < 10]
print(new_list)

Zuletzt aktualisiert am 4. August 2021