Der Mechanismus if __name__ == ”__main__”

Heute soll es um die Konstruktion if __name__ == ”__main__” gehen. Wir werden sehen, was diese Kontrollstruktur inhaltlich aussagt und zu welchem Zweck sie eingesetzt werden kann.

Inhalt

Kurz und Gut

Bringen wir es auf den Punkt: Die Konstruktion if __name_ == ”__main__” wird eingesetzt, weil eine Datei grundsätzlich auf 2 Arten verwendet werden kann. Sie kann:

  1. Als eigenständiges Programm ablaufen (bspw. wenn wir sie in der Konsole mit python datei.py öffnen).
  2. Elemente wie Funktionen, Klassen oder Konstanten enthalten, die wir in ein anderes Programm importieren.

Der springende Punkt ist, dass durch die Verwendung der Kontrollstruktur nicht 2 Dateien angelegt werden müssen (für jede Anwendung eine). Beide Anwendungen können mit Hilfe von if __name__ == ”__main__” durch eine einzige Datei bedient werden.

Der Mechanismus

Um zu verstehen, zu welchem Zweck die Konstruktion eingesetzt wird, müssen wir uns ansehen, was sie returniert.

Vorweg dies: __name__ ist eine Systemvariable. Sie speichert den Bezeichner einer Skriptdatei. Die Ausprägung von __name__ kann grundsätzlich 2 Werte annehmen:

  1. ”__main__” (wenn name aus dem Startskript eines Programms aufgerufen wird)
  2. Den Modulnamen (Name der Datei, aus der __name__ aufgerufen wird, wenn diese importiert wird)

Starten wir ein Python Programm indem wir eine py-Datei aufrufen und wird dort __name__ aufgerufen, vergibt das System der Variable den Bezeichner ”__main__”. Importieren wir in diese Datei allerdings in ein anderes Modul, erhält sie einen Bezeichner, der dem Dateinamen entspricht.

Angenommen wir haben die unten aufgeführte Dateistruktur für ein Python-Programm. Es existiert eine run.py Datei, mit der eine Fibonacci-Zahl ausgegeben wird. Das Programm ist dafür designt, aus der Konsole des Betriebssystems aufgerufen zu werden mit ‚python run.py 10‘ (wobei 10 ein beliebiges Userargument ist). Das Modul ressources.py enthält eine entsprechende Funktion fibonacci welche in die run.py importiert wird. Damit wir sehen, welchen Wert __name__ in beiden oben aufgeführten Szenarien annimmt, ist der Befehl print(‚Wert von __name__‘ … ) eingefügt.

\Projekt

run.py
ressources.py

Hier ein Einblick in die Dateien:

run.py:

from ressources import fibonacci

n = int(sys.argv[1])
print(fibonacci(n))
print('Wert von __name__ in run.py:' __name__)

ressources.py:

def fibonacci(n):
    x = 0
    y = 1
    for i in range(n):
        x, y = y, x + y
    return x

print('Wert von __name__ in ressources.py:' __name__)

Führen wir nun in der Konsole des Betriebssystems folgenden Befehl aus:

python run.py 10

55
Wert von __name__ in ressources.py: ressources
Wert von __name__ in run.py: __main__

Wie wir sehen, nimmt __name__ je nach Ort, von welchem aus der Wert abgerufen wird unterschiedlich Ausprägungen an.

Der Nutzenaspekt

Nun zum konkreten Einsatz des Mechanismus: Wie machen wir von if __name_ == ”__main__” gebrauch? Dazu formulieren wir mit Hilfe des Fibonacci-Beispiels ein konkretes Ziel:

Wie wollen die Funktion fibonacci implementieren. Diese soll zum einen als eigenständiges Programm abrufbar sein – d.h. der User soll eine Position der Fibonacci-Folge als Argument übergeben können und er soll die entsprechende Fibonacci-Zahl angezeigt bekommen. Zum Anderen soll die Funktion fibonacci durch andere Programme importierbar bleiben.

Um der Zielsetzung zu entsprechen, können wir eine Datei fibonacci.py mit folgendem Quellcode erstellen:

def fibonacci(n):
    x = 0
    y = 1
    for i in range(n):
        x, y = y, x + y
    return x

if __name__ == "__main__":

    import sys 

    n = int(sys.argv[1])    
    print(fibonacci(10))

Wenn nun die Datei in der Konsole des Betriebssystems aufgerufen wird, ist der Wert von __name__ gleich ”__main__”. In dem Fall wird also der Anweisungsblock der Kontrollstruktur ausgeführt. Wird dagegen die Datei durch eine andere Datei importiert, ist der Wert von __name__ gleich ”__fibonacci__”. Entsprechend wird der Anweisungsblock nicht aufgeführt (was auch keinesfalls passieren soll, da aufgrund der fehlenden Usereingabe ein ValueError auftritt).

Ein weiterer Nutzenaspekt, den der Mechanismus bietet, ist folgender: Wir können komplexe Modultests darin durchführen. Nehmen wir an, wir haben ein Modul, in welchem eine Klasse implementiert ist. Diese Klasse wird in einem komplexen Programmablauf benötigt. Die Frage ist nun, wie können wir die Klasse testen, ohne den gesamten Quellcode des Programms zu durchlaufen? Richtig: Mit Hilfe von if __name__ == ”__main__”. In den Anweisungsblock können wir ein Testszenario entwickeln, welches mit dem Aufruf der Datei durchlaufen wird.

Fazit

Die Konstruktion if __name__ == ”__main__” wird eingesetzt um eine Python Datei als eigenständiges Programm zu nutzen und einzelne Elemente dieser Datei importierbar zu machen. Der Mechanismus wird auch dazu genutzt, komplexe Modultests du implementieren.