Lernpfad
Der Bedingungsblock mit if __name__ == "__main__" taucht in Python-Code häufig auf. Diese Zeile wirkt zunächst kryptisch, und viele Einsteiger verwenden sie, ohne wirklich zu wissen, was sie macht oder ob sie überhaupt nötig ist. Auch Programmierer aus anderen Sprachen missverstehen und übernutzen diese Idiomatik leicht.
Dieses Tutorial erklärt die Bedeutung von Pythons Idiom if__name__ == "__main__" und zeigt, wie und wann du es einsetzt.
Werde Dateningenieur
__name__ und "__main__" verstehen
Das Idiom if __name__ == "__main__" ist eine if-Anweisung, die auf Gleichheit prüft.
Der erste Operand links vom Gleichheitsoperator == ist das Attribut __name__. Python-Namen mit führenden und abschließenden doppelten Unterstrichen sind spezielle Bezeichner. Jedes Modul besitzt ein __name__-Attribut. Python setzt diese Variable auf den Modulnamen, den das Importsystem nutzt, um jedes Modul eindeutig zu identifizieren.
Befindet sich das Modul jedoch in der Top-Level-Code-Umgebung, also als Einstiegspunkt des Programms, setzt Python das Attribut __name__ auf die Zeichenkette "__main__".
Schauen wir uns Beispiele an. Erstelle ein Skript namens exploring_name_main.py:
# exploring_name_main.py
import random
print(__name__)
print(random.__name__)
Dieses Skript kannst du im Terminal mit folgendem Befehl direkt ausführen:
$ python exploring_name_main.py
__main__
random
Das Skript exploring_name_main.py läuft in der Top-Level-Code-Umgebung, weil es der Einstiegspunkt des Programms ist. Daher ist die Variable __name__ auf die Zeichenkette "__main__" gesetzt.
Das Modul random wurde hingegen importiert und befindet sich nicht in der Top-Level-Code-Umgebung. Sein Attribut __name__ ist auf den Modulnamen gesetzt.
Als Nächstes erstellen wir ein neues Skript more_exploration.py, das das erste Skript importiert:
# more_exploration.py
import exploring_name_main
Führe dieses Skript im Terminal mit folgendem Befehl aus:
$ python more_exploration.py
exploring_name_main
random
Der Code eines Moduls wird beim Import ausgeführt. Beim Ausführen von more_exploration.py siehst du daher die Ausgabe der beiden print()-Aufrufe aus exploring_name_main.py. Da exploring_name_main.py nicht mehr der Einstiegspunkt ist, wird sein Attribut __name__ auf den Skriptnamen gesetzt, nicht auf "__main__".
Der Bedingungsblock if __name__ == "__main__"
Die Variable __name__ zeigt an, ob ein Modul der Haupteinstiegspunkt eines Programms ist. Ein Modul kann daher Code enthalten, der nur ausgeführt wird, wenn es direkt als Skript gestartet wird, nicht aber beim Import. Solcher Code steht im Bedingungsblock if __name__ == "__main__":
# exploring_name_main.py
import random
print(__name__)
print(random.__name__)
number = random.randint(1, 10)
if __name__ == "__main__":
print("This script is in the top-level code environment")
print(f"The number is {number}")
Der Code in exploring_name_main.py enthält jetzt einen if __name__ == "__main__"-Block. Prüfen wir, was bei direkter Ausführung passiert:
$ python exploring_name_main.py
__main__
random
This script is in the top-level code environment
The number is 10
Wenn das Skript direkt ausgeführt wird, ist __name__ auf "__main__" gesetzt. Die Bedingung im if-Statement ist daher True, und Python führt den Code im if-Block aus.
Wird das Modul hingegen importiert, ist __name__ auf den Modulnamen gesetzt und der if-Block wird nicht ausgeführt. Erinnern wir uns: Das Skript more_exploration.py importiert exploring_name_main:
$ python more_exploration.py
exploring_name_main
random
Das Programm ruft die print()-Funktionen in exploring_name_main.py nicht auf. Sie stehen in einem Bedingungsblock, der nicht ausgeführt wird, weil __name__ nicht "__main__" entspricht.
Best Practices und Tipps für Pythons if __name__ == "__main__"
Pythons Idiom if __name__ == "__main__" kommt zum Einsatz, wenn Code nur laufen soll, wenn eine Datei als Skript gestartet wird – nicht, wenn sie als Modul importiert wird. Der Unterschied zwischen den Begriffen Skript und Modul liegt nur in der Verwendung der Datei. Beides sind Dateien mit der Endung .py.
Ein gängiger Anwendungsfall: Ein Skript stellt Variablen, Funktionen und Klassen bereit, die auch in anderen Programmen genutzt werden können. Hier ein Beispiel mit shapes.py:
# shapes.py
import math
def find_area_of_circle(radius):
return math.pi * radius ** 2
def find_area_of_rectangle(width, height):
return width * height
if __name__ == "__main__":
shape = int(input("Enter 1 for circle, 2 for rectangle: "))
if shape == 1:
radius = int(input("Enter radius: "))
print(f"The area of the circle is {find_area_of_circle(radius)}")
elif shape == 2:
width = int(input("Enter width: "))
height = int(input("Enter height: "))
print(f"The area of the rectangle is {find_area_of_rectangle(width, height)}")
Enter 1 for circle, 2 for rectangle: 2
Enter width: 10
Enter height: 20
The area of the rectangle is 200
Dieser Code braucht das Idiom if __name__ == "__main__" nicht, wenn er immer nur als Skript laufen soll. Mit der Bedingung kann er jedoch als Modul importiert werden, ohne die Zeilen im if-Block auszuführen. Betrachte dazu more_shapes.py:
# more_shapes.py
import shapes
radius = 5
print(f"The area of the circle defined in 'more_shapes.py' is: "
f"{shapes.find_area_of_circle(radius)}")
The area of the circle defined in 'more_shapes.py' is: 78.53981633974483
Dieses neue Skript more_shapes.py kann dank des Imports die in shapes.py definierten Funktionen verwenden. Der Code im Block if __name__ == "__main__" in shapes.py wird jedoch nicht ausgeführt. Ohne das if-Statement in shapes.py würde beim Import das gesamte Skript laufen.
Den Block if __name__ == "__main__" für Nutzereingaben zu verwenden, ist ein verbreiteter Ansatz. Beim Import als Modul werden die Eingaben ausgelassen, bei direkter Ausführung als Top-Level-Code hingegen abgefragt.
Einsatz einer main()-Funktion
Es ist Best Practice, im Block if __name__ == "__main__" so wenig wie möglich zu platzieren, um die Lesbarkeit zu erhöhen. Üblich ist deshalb, den Ablauf in eine Funktion auszulagern und diese im Bedingungsblock aufzurufen. Oft heißt diese Funktion main(), aber jeder Funktionsname ist zulässig:
# shapes.py
import math
def find_area_of_circle(radius):
return math.pi * radius ** 2
def find_area_of_rectangle(width, height):
return width * height
def main():
shape = int(input("Enter 1 for circle, 2 for rectangle: "))
if shape == 1:
radius = int(input("Enter radius: "))
print(f"The area of the circle is {find_area_of_circle(radius)}")
elif shape == 2:
width = int(input("Enter width: "))
height = int(input("Enter height: "))
print(f"The area of the rectangle is {find_area_of_rectangle(width, height)}")
if __name__ == "__main__":
main()
Der Code in main() entspricht genau dem, der zuvor direkt im Block if __name__ == "__main__" stand.
In Python ist main() – anders als in einigen anderen Sprachen – nicht als fester Programmeinstiegspunkt vorgeschrieben. Der Einsatz von main() und des Idioms if __name__ == "__main__" ist optional und nur nötig, wenn der Code sowohl als eigenständiges Skript als auch als Modul dienen soll.
Ein weiterer verbreiteter Einsatzzweck für if __name__ == "__main__" ist das Einbinden einfacher Tests ins Skript. Diese laufen bei direkter Ausführung, nicht aber beim Import aus einem anderen Modul. Für mehr als triviale Fälle empfiehlt es sich jedoch, Tests in ein eigenes Testmodul auszulagern.
Fazit
Pythons if __name__ == "__main__" ist hilfreich, um Code nur dann auszuführen, wenn ein Skript direkt gestartet wird – nicht jedoch beim Import. Der Python-Interpreter setzt __name__ auf den Modulnamen, wenn importiert wird, und auf die Zeichenkette "__main__", wenn das Modul der Haupteinstiegspunkt ist.
Anders als in manchen anderen Sprachen sind die Funktion main() und das Idiom if __name__ == "__main__" keine Voraussetzung, um Python-Code auszuführen, sondern Werkzeuge, die du bei Bedarf nutzen kannst.
Werde Dateningenieur
Ich habe Physik und Mathematik auf UG-Ebene an der Universität Malta studiert. Dann zog ich nach London und machte meinen Doktor in Physik am Imperial College. Ich habe an neuartigen optischen Techniken zur Abbildung der menschlichen Netzhaut gearbeitet. Jetzt konzentriere ich mich darauf, über Python zu schreiben, über Python zu kommunizieren und Python zu unterrichten.
