__main__ — Top-level-Codeumgebung


In Python wird der spezielle Name __main__ für zwei wichtige Konstrukte verwendet:

  1. der Name der Top-Level-Umgebung des Programms, die mit dem Ausdruck __name__ == '__main__' überprüft werden kann; und

  2. die Datei __main__.py in Python-Paketen.

Beide Mechanismen beziehen sich auf Python-Module; wie Benutzer mit ihnen interagieren und wie sie miteinander interagieren. Sie werden unten detailliert erläutert. Wenn Sie neu in Python-Modulen sind, lesen Sie den Tutorial-Abschnitt Module für eine Einführung.

__name__ == '__main__'

Wenn ein Python-Modul oder -Paket importiert wird, wird __name__ auf den Namen des Moduls gesetzt. Normalerweise ist dies der Name der Python-Datei selbst ohne die Erweiterung .py.

>>> import configparser
>>> configparser.__name__
'configparser'

Wenn die Datei Teil eines Pakets ist, enthält __name__ auch den Pfad des übergeordneten Pakets.

>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'

Wenn das Modul jedoch in der Top-Level-Codeumgebung ausgeführt wird, wird sein __name__ auf den String '__main__' gesetzt.

Was ist die "Top-Level-Codeumgebung"?

__main__ ist der Name der Umgebung, in der Top-Level-Code ausgeführt wird. "Top-Level-Code" ist das erste vom Benutzer angegebene Python-Modul, das mit der Ausführung beginnt. Es ist "Top-Level", weil es alle anderen Module importiert, die das Programm benötigt. Manchmal wird "Top-Level-Code" als Einstiegspunkt für die Anwendung bezeichnet.

Die Top-Level-Codeumgebung kann sein:

  • der Gültigkeitsbereich einer interaktiven Eingabeaufforderung

    >>> __name__
    '__main__'
    
  • das Python-Modul, das dem Python-Interpreter als Dateiargument übergeben wird

    $ python helloworld.py
    Hello, world!
    
  • das Python-Modul oder -Paket, das dem Python-Interpreter mit dem Argument -m übergeben wird

    $ python -m tarfile
    usage: tarfile.py [-h] [-v] (...)
    
  • Python-Code, der vom Python-Interpreter aus der Standardeingabe gelesen wird

    $ echo "import this" | python
    The Zen of Python, by Tim Peters
    
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
    
  • Python-Code, der dem Python-Interpreter mit dem Argument -c übergeben wird

    $ python -c "import this"
    The Zen of Python, by Tim Peters
    
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
    

In jeder dieser Situationen wird der __name__ des Top-Level-Moduls auf '__main__' gesetzt.

Daher kann ein Modul erkennen, ob es in der Top-Level-Umgebung ausgeführt wird oder nicht, indem es sein eigenes __name__ überprüft. Dies ermöglicht ein gängiges Idiom zur bedingten Ausführung von Code, wenn das Modul nicht über eine Importanweisung initialisiert wird.

if __name__ == '__main__':
    # Execute when the module is not initialized from an import statement.
    ...

Siehe auch

Für einen detaillierteren Einblick, wie __name__ in allen Situationen gesetzt wird, siehe den Tutorial-Abschnitt Module.

Idiomatischer Gebrauch

Einige Module enthalten Code, der nur für die Skriptnutzung bestimmt ist, wie z. B. das Parsen von Befehlszeilenargumenten oder das Abrufen von Daten aus der Standardeingabe. Wenn ein solches Modul von einem anderen Modul importiert würde, z. B. um es zu testen, würde der Skriptcode unbeabsichtigt mit ausgeführt.

Hier ist der Codeblock if __name__ == '__main__' nützlich. Code innerhalb dieses Blocks wird nicht ausgeführt, es sei denn, das Modul wird in der Top-Level-Umgebung ausgeführt.

Wenige Anweisungen wie möglich in den Block unter if __name__ == '__main__' zu setzen, kann die Klarheit und Korrektheit des Codes verbessern. Am häufigsten kapselt eine Funktion namens main das Hauptverhalten des Programms.

# echo.py

import shlex
import sys

def echo(phrase: str) -> None:
   """A dummy wrapper around print."""
   # for demonstration purposes, you can imagine that there is some
   # valuable and reusable logic inside this function
   print(phrase)

def main() -> int:
    """Echo the input arguments to standard output"""
    phrase = shlex.join(sys.argv)
    echo(phrase)
    return 0

if __name__ == '__main__':
    sys.exit(main())  # next section explains the use of sys.exit

Beachten Sie, dass, wenn das Modul den Code nicht innerhalb der Funktion main kapselt, sondern ihn direkt in den Block if __name__ == '__main__' legt, die Variable phrase global für das gesamte Modul wäre. Dies ist fehleranfällig, da andere Funktionen innerhalb des Moduls möglicherweise unbeabsichtigt die globale Variable anstelle eines lokalen Namens verwenden. Eine Funktion main löst dieses Problem.

Die Verwendung einer Funktion main hat den zusätzlichen Vorteil, dass die Funktion echo selbst isoliert und woanders importierbar ist. Wenn echo.py importiert wird, werden die Funktionen echo und main definiert, aber keine von ihnen wird aufgerufen, da __name__ != '__main__'.

Verpackungsüberlegungen

main-Funktionen werden oft verwendet, um Kommandozeilen-Tools zu erstellen, indem sie als Einstiegspunkte für Konsolenskripte angegeben werden. Wenn dies geschieht, fügt pip den Funktionsaufruf in ein Vorlagenskript ein, wobei der Rückgabewert von main an sys.exit() übergeben wird. Zum Beispiel:

sys.exit(main())

Da der Aufruf von main in sys.exit() eingekapselt ist, wird erwartet, dass Ihre Funktion einen Wert zurückgibt, der als Eingabe für sys.exit() akzeptabel ist; typischerweise eine Ganzzahl oder None (was implizit zurückgegeben wird, wenn Ihre Funktion keine Rückgabeanweisung hat).

Indem wir diese Konvention proaktiv selbst befolgen, wird unser Modul das gleiche Verhalten aufweisen, wenn es direkt ausgeführt wird (d. h. python echo.py), wie wenn wir es später als Konsolen-Skript-Einstiegspunkt in einem pip-installierbaren Paket verpacken.

Seien Sie insbesondere vorsichtig, wenn Sie Zeichenketten aus Ihrer main-Funktion zurückgeben. sys.exit() interpretiert ein Zeichenkettenargument als Fehlermeldung, sodass Ihr Programm einen Exit-Code von 1 hat, der einen Fehler anzeigt, und die Zeichenkette wird an sys.stderr geschrieben. Das frühere Beispiel echo.py veranschaulicht die Konvention sys.exit(main()).

Siehe auch

Python Packaging User Guide enthält eine Sammlung von Tutorials und Referenzen zur Verteilung und Installation von Python-Paketen mit modernen Werkzeugen.

__main__.py in Python-Paketen

Wenn Sie mit Python-Paketen nicht vertraut sind, lesen Sie den Abschnitt Pakete des Tutorials. Am häufigsten wird die Datei __main__.py verwendet, um eine Befehlszeilenschnittstelle für ein Paket bereitzustellen. Betrachten Sie das folgende hypothetische Paket "bandclass":

bandclass
  ├── __init__.py
  ├── __main__.py
  └── student.py

Die Datei __main__.py wird ausgeführt, wenn das Paket selbst direkt über die Befehlszeile mit dem Flag -m aufgerufen wird. Zum Beispiel:

$ python -m bandclass

Dieser Befehl führt __main__.py aus. Wie Sie diesen Mechanismus nutzen, hängt von der Art des Pakets ab, das Sie schreiben. In diesem hypothetischen Fall wäre es sinnvoll, dem Lehrer zu erlauben, nach Schülern zu suchen.

# bandclass/__main__.py

import sys
from .student import search_students

student_name = sys.argv[1] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')

Beachten Sie, dass from .student import search_students ein Beispiel für einen relativen Import ist. Dieser Importstil kann beim Referenzieren von Modulen innerhalb eines Pakets verwendet werden. Weitere Details finden Sie unter Intra-Package-Referenzen im Abschnitt Module des Tutorials.

Idiomatischer Gebrauch

Der Inhalt von __main__.py wird typischerweise nicht mit einem Block if __name__ == '__main__' umzäunt. Stattdessen werden diese Dateien kurz gehalten und importieren Funktionen aus anderen Modulen zur Ausführung. Diese anderen Module können dann leicht per Unit-Test getestet und ordnungsgemäß wiederverwendet werden.

Wenn ein Block if __name__ == '__main__' verwendet wird, funktioniert er immer noch wie erwartet für eine __main__.py-Datei innerhalb eines Pakets, da ihr __name__-Attribut den Pfad des Pakets enthält, wenn es importiert wird.

>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'

Dies funktioniert jedoch nicht für __main__.py-Dateien im Stammverzeichnis einer .zip-Datei. Daher ist aus Gründen der Konsistenz eine minimale __main__.py ohne __name__-Prüfung vorzuziehen.

Siehe auch

Siehe venv für ein Beispiel eines Pakets mit einer minimalen __main__.py in der Standardbibliothek. Es enthält keinen Block if __name__ == '__main__'. Sie können es mit python -m venv [Verzeichnis] aufrufen.

Siehe runpy für weitere Details zum Flag -m für die Interpreter-Executable.

Siehe zipapp, wie Anwendungen ausgeführt werden, die als .zip-Dateien verpackt sind. In diesem Fall sucht Python nach einer Datei __main__.py im Stammverzeichnis des Archivs.

import __main__

Unabhängig davon, mit welchem Modul ein Python-Programm gestartet wurde, können andere Module, die innerhalb desselben Programms laufen, den Gültigkeitsbereich (Namensraum) der Top-Level-Umgebung importieren, indem sie das Modul __main__ importieren. Dies importiert keine Datei __main__.py, sondern jenes Modul, das den speziellen Namen '__main__' erhalten hat.

Hier ist ein Beispielmodul, das den __main__-Namensraum verbraucht:

# namely.py

import __main__

def did_user_define_their_name():
    return 'my_name' in dir(__main__)

def print_user_name():
    if not did_user_define_their_name():
        raise ValueError('Define the variable `my_name`!')

    print(__main__.my_name)

Die Beispielnutzung dieses Moduls könnte wie folgt aussehen:

# start.py

import sys

from namely import print_user_name

# my_name = "Dinsdale"

def main():
    try:
        print_user_name()
    except ValueError as ve:
        return str(ve)

if __name__ == "__main__":
    sys.exit(main())

Wenn wir nun unser Programm starten würden, sähe das Ergebnis wie folgt aus:

$ python start.py
Define the variable `my_name`!

Der Exit-Code des Programms wäre 1, was auf einen Fehler hinweist. Das Auskommentieren der Zeile mit my_name = "Dinsdale" behebt das Programm, und es wird nun mit dem Statuscode 0 beendet, was Erfolg anzeigt.

$ python start.py
Dinsdale

Beachten Sie, dass der Import von __main__ keine Probleme mit unbeabsichtigter Ausführung von Top-Level-Code verursacht, der für die Skriptnutzung bestimmt ist und sich im Block if __name__ == "__main__" des Moduls start befindet. Warum funktioniert das?

Python fügt zu Beginn des Interpreters ein leeres Modul __main__ in sys.modules ein und füllt es durch Ausführung von Top-Level-Code. In unserem Beispiel ist dies das Modul start, das Zeile für Zeile ausgeführt wird und namely importiert. namely wiederum importiert __main__ (was eigentlich start ist). Das ist ein Importzyklus! Glücklicherweise wird, da das teilweise gefüllte Modul __main__ in sys.modules vorhanden ist, dieses an namely übergeben. Siehe Spezielle Überlegungen für __main__ im Referenzhandbuch des Importsystems für Details, wie dies funktioniert.

Die Python REPL ist ein weiteres Beispiel für eine "Top-Level-Umgebung", daher wird alles, was in der REPL definiert wird, Teil des __main__-Gültigkeitsbereichs.

>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky

Der __main__-Gültigkeitsbereich wird in der Implementierung von pdb und rlcompleter verwendet.