Wie man lesbaren Code schreibt mit PEP8 – Teil 3

Einrückung („Indentation“)

„Es sollte einen – und vorzugsweise nur einen – offensichtlichen Weg geben, es zu tun.“

– Das Zen von Python

Die Einrückung bzw. der führende Leerraum ist in Python extrem wichtig. Die Einrückungsebene von Codezeilen in Python bestimmt, wie Anweisungen gruppiert werden.

Hierzu das folgende Beispiel:

x = 3
if x > 5:
    print('x is larger than 5')

Die eingerückte print-Anweisung teilt Python mit, dass sie nur ausgeführt werden soll, wenn die if-Anweisung True zurückgibt. Die gleiche Einrückung wird verwendet, um Python mitzuteilen, welcher Code ausgeführt werden soll, wenn eine Funktion aufgerufen wird oder welcher Code zu einer bestimmten Klasse gehört.

Die wichtigsten Einrückungsregeln, die in PEP 8 festgelegt sind, lauten wie folgt:

  • Es sind 4 aufeinanderfolgende Leerzeichen zu verwenden, um eine Einrückung anzuzeigen.
  • Es sind bevorzugt Leerzeichen gegenüber Tabulatoren zu verwenden.

Tabulatoren vs. Leerzeichen

Wie bereits erwähnt, sollte man bei der Einrückung von Code Leerzeichen anstelle von Tabulatoren verwenden. Man kann die Einstellungen im Texteditor so anpassen, dass 4 Leerzeichen anstelle eines Tabulatorzeichens ausgegeben werden, wenn man die Tabulatortaste drückt.

Python 3 erlaubt keine Vermischung von Tabulatoren und Leerzeichen. Wenn man also diese Version verwendet, werden die Fehler automatisch ausgegeben:

$ python3 code.py
  File "code.py", line 3
    print(i, j)
              ^
TabError: inconsistent use of tabs and spaces in indentation

Man kann Python-Code entweder mit Tabulatoren oder mit Leerzeichen schreiben, um die Einrückung anzuzeigen. Man nuss jedoch bei der Wahl konsequent sein. Andernfalls wird der Code nicht laufen. PEP 8 empfiehlt, dass man immer 4 aufeinanderfolgende Leerzeichen zur Kennzeichnung der Einrückung verwendet.

Einrückung nach Zeilenumbrüchen

Wenn man Zeilenumbrüche verwendet, um die Zeilenlänge auf weniger als 79 Zeichen zu begrenzen, ist es sinnvoll, zur Verbesserung der Lesbarkeit Einrückungen vorzunehmen. Sie ermöglicht es dem Leser, zwischen zwei Codezeilen und einer einzigen Codezeile, die sich über zwei Zeilen erstreckt, zu unterscheiden. Es gibt zwei Arten der Einrückung, die man verwendet kann.

Die erste besteht darin, den eingerückten Block am ersten Begrenzungszeichen auszurichten:

def function(arg_one, arg_two,
             arg_three, arg_four):

    return arg_one

Manchmal werden nur 4 Leerzeichen benötigt, um mit dem öffnenden Begrenzungszeichen übereinzustimmen. Dies ist häufig bei if-Anweisungen der Fall, die sich über mehrere Zeilen erstrecken, da if, Leerzeichen und öffnende Klammer zusammen 4 Zeichen ergeben. In diesem Fall kann es schwierig sein, festzustellen, wo der verschachtelte Codeblock innerhalb der if-Anweisung beginnt:

x = 5
if (x > 3 and
    x < 10):
    print(x)

Für diesen Fall bietet PEP 8 zwei Alternativen, um die Lesbarkeit zu verbessern:

– Man fügt einen Kommentar nach der letzten Bedingung ein. Aufgrund der Syntaxhervorhebung in den meisten Editoren wird dies die Bedingungen vom verschachtelten Code trennen:

x = 5
if (x > 3 and
    x < 10):
    # Both conditions satisfied
    print(x)

– Man fügt eine zusätzliche Einrückung in der Zeilenfortsetzung hinzu:

x = 5
if (x > 3 and
        x < 10):
    print(x)

Eine alternative Form des Einzugs nach einem Zeilenumbruch ist der hängende Einzug. Dies ist ein typografischer Begriff und bedeutet, dass jede Zeile außer der ersten in einem Absatz oder einer Anweisung eingerückt ist. Man kann einen hängenden Einzug verwenden, um eine Fortsetzung einer Codezeile visuell darzustellen.

Hier ist ein Beispiel:

var = function(
    arg_one, arg_two,
    arg_three, arg_four)

Hinweis: Wenn man einen hängenden Einzug verwendet, dürfen sich in der ersten Zeile keine Argumente befinden.

Das folgende Beispiel ist nicht PEP 8-konform:

# nicht empfohlen
var = function(arg_one, arg_two,
    arg_three, arg_four)

Wenn man eine hängende Einrückung verwendet, fügt man eine zusätzliche Einrückung hinzu, um die fortgesetzte Zeile von dem in der Funktion enthaltenen Code zu unterscheiden. Das folgende Beispiel ist schwer lesbar, weil der Code innerhalb der Funktion auf der gleichen Einrückungsebene liegt wie die fortgesetzten Zeilen:

# nicht empfohlen
def function(
    arg_one, arg_two,
    arg_three, arg_four):

    return arg_one

Stattdessen ist es besser, einen doppelten Einzug in der Zeilenfortsetzung zu verwenden. Dies hilft, zwischen Funktionsargumenten und dem Funktionsrumpf zu unterscheiden, und verbessert die Lesbarkeit:

def function(
        arg_one, arg_two,
        arg_three, arg_four):

    return arg_one

Wenn man PEP 8-konformen Code schreibt, ist man aufgrund der Zeilenbegrenzung auf 79 Zeichen gezwungen, Zeilenumbrüche im Code einzufügen. Um die Lesbarkeit zu verbessern, sollte man eine fortgesetzte Zeile einrücken, um zu zeigen, dass es sich um eine fortgesetzte Zeile handelt. Es gibt zwei Möglichkeiten, dies zu tun. Die erste besteht darin, den eingerückten Block an dem einleitenden Begrenzungszeichen auszurichten. Die zweite ist die Verwendung eines hängenden Einzugs. Es ist freigestellt, welche Methode des Einrückens man nach einem Zeilenumbruch verwendet.

Wo wird die schließende Klammer gesetzt?

Mit Hilfe von Zeilenumbrüchen kann man Zeilen innerhalb von Klammern, geschweiften Klammern oder geschweiften Klammern umbrechen. Die schließende Klammer kann leicht vergessen werden, aber es ist wichtig, sie an einer sinnvollen Stelle zu platzieren. Ansonsten kann sie den Leser verwirren. PEP 8 bietet zwei Optionen für die Position der schließenden Klammer in impliziten Zeilenfortsetzungen:

– Man richtet die schließende Klammer mit dem ersten Nicht-Leerzeichen der vorherigen Zeile aus:

list_of_numbers = [
    1, 2, 3,
    4, 5, 6,
    7, 8, 9
    ]

– Man richtet die schließende Klammer mit dem ersten Zeichen der Zeile aus, mit der das Konstrukt beginnt:

list_of_numbers = [
    1, 2, 3,
    4, 5, 6,
    7, 8, 9
]

Es steht frei, welche Option man verwendet. Aber wie immer ist Konsistenz der Schlüssel, also sollte man versuchen, sich an eine der oben genannten Methoden zu halten.