Was bewirkt dies?
if __name__ == "__main__":
print("Hello world!")
Was bewirkt dies?
if __name__ == "__main__":
print("Hello world!")
Es handelt sich um einen Standardcode, der die Benutzer davor schützt, das Skript versehentlich aufzurufen, wenn sie es nicht beabsichtigt haben. Hier sind einige häufige Probleme, wenn der Guard in einem Skript weggelassen wird:
Wenn Sie das Guardless-Skript in ein anderes Skript importieren (z. B. import my_script_without_a_name_eq_main_guard
), dann löst das zweite Skript die Ausführung des ersten aus zum Zeitpunkt der Einfuhr et unter Verwendung der Befehlszeilenargumente des zweiten Skripts . Dies ist fast immer ein Fehler.
Wenn Sie eine benutzerdefinierte Klasse im Guardless-Skript haben und sie in einer Pickle-Datei speichern, löst das Entpicken in einem anderen Skript einen Import des Guardless-Skripts aus, mit den gleichen Problemen, die im vorherigen Punkt beschrieben wurden.
Um besser zu verstehen, warum und wie dies wichtig ist, müssen wir einen Schritt zurückgehen, um zu verstehen, wie Python Skripte initialisiert und wie dies mit seinem Modul-Import-Mechanismus zusammenhängt.
Wann immer der Python-Interpreter eine Quelldatei liest, tut er zwei Dinge:
setzt er einige spezielle Variablen wie __name__
und dann
wird der gesamte in der Datei enthaltene Code ausgeführt.
Schauen wir uns an, wie das funktioniert und wie es sich auf Ihre Frage nach der __name__
Prüfungen, die wir immer in Python-Skripten sehen.
Lassen Sie uns anhand eines etwas anderen Codebeispiels untersuchen, wie Importe und Skripte funktionieren. Nehmen wir an, das Folgende befindet sich in einer Datei namens foo.py
.
# Suppose this is foo.py.
print("before import")
import math
print("before functionA")
def functionA():
print("Function A")
print("before functionB")
def functionB():
print("Function B {}".format(math.sqrt(100)))
print("before __name__ guard")
if __name__ == '__main__':
functionA()
functionB()
print("after __name__ guard")
Wenn der Python-Interpreter eine Quelldatei liest, definiert er zunächst einige spezielle Variablen. In diesem Fall kümmern wir uns um die __name__
variabel.
Wenn Ihr Modul das Hauptprogramm ist
Wenn Sie Ihr Modul (die Quelldatei) als Hauptprogramm ausführen, z. B.
python foo.py
wird der Interpreter die fest kodierte Zeichenkette "__main__"
zum __name__
Variable, d.h.
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Wenn Ihr Modul von einem anderen importiert wird
Nehmen wir andererseits an, ein anderes Modul ist das Hauptprogramm und importiert Ihr Modul. Das bedeutet, dass es eine Anweisung wie diese im Hauptprogramm oder in einem anderen Modul gibt, das das Hauptprogramm importiert:
# Suppose this is in some other main program.
import foo
Der Interpreter sucht nach Ihrer foo.py
Datei (zusammen mit der Suche nach einigen anderen Varianten), und vor der Ausführung dieses Moduls wird es den Namen "foo"
aus der Import-Anweisung in die __name__
Variable, d.h.
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Nachdem die speziellen Variablen eingerichtet sind, führt der Interpreter den gesamten Code des Moduls aus, eine Anweisung nach der anderen. Vielleicht möchten Sie ein weiteres Fenster auf der Seite mit dem Codebeispiel öffnen, damit Sie dieser Erklärung folgen können.
Immer
Er druckt die Zeichenfolge "before import"
(ohne Anführungszeichen).
Es lädt die math
Modul und weist es einer Variablen namens math
. Dies ist gleichbedeutend mit dem Ersetzen von import math
mit dem folgenden (beachten Sie, dass __import__
ist eine Low-Level-Funktion in Python, die eine Zeichenkette annimmt und den eigentlichen Import auslöst):
math = import("math")
Er druckt die Zeichenfolge "before functionA"
.
Sie führt die def
Block, wobei ein Funktionsobjekt erstellt wird, das dann einer Variablen namens functionA
.
Er druckt die Zeichenfolge "before functionB"
.
Sie führt die zweite def
Block, erstellt ein weiteres Funktionsobjekt und weist es einer Variablen namens functionB
.
Er druckt die Zeichenfolge "before __name__ guard"
.
Nur wenn Ihr Modul das Hauptprogramm ist
__name__
wurde tatsächlich auf "__main__"
und ruft die beiden Funktionen auf, wobei die Zeichenketten gedruckt werden "Function A"
et "Function B 10.0"
.Nur wenn Ihr Modul von einem anderen importiert wird
__name__
wird sein "foo"
, nicht "__main__"
und überspringt den Textkörper der if
Erklärung.Immer
"after __name__ guard"
in beiden Situationen.Zusammenfassung
Zusammenfassend lässt sich sagen, was in den beiden Fällen gedruckt werden würde:
# What gets printed if foo is the main program
before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard
# What gets printed if foo is imported as a regular module
before import
before functionA
before functionB
before __name__ guard
after __name__ guard
Man könnte sich natürlich fragen, warum das jemand will. Nun, manchmal möchte man einen .py
Datei, die sowohl von anderen Programmen und/oder Modulen als Modul verwendet werden kann, als auch als Hauptprogramm selbst ausgeführt werden kann. Beispiele:
Ihr Modul ist eine Bibliothek, aber Sie möchten einen Skriptmodus haben, in dem es einige Unit-Tests oder eine Demo ausführt.
Ihr Modul wird nur als Hauptprogramm verwendet, hat aber einige Unit-Tests, und das Test-Framework funktioniert durch den Import von .py
Dateien wie Ihr Skript und die Ausführung spezieller Testfunktionen. Sie wollen nicht, dass das Skript ausgeführt wird, nur weil es das Modul importiert.
Ihr Modul wird hauptsächlich als Hauptprogramm verwendet, bietet aber auch eine programmiererfreundliche API für fortgeschrittene Benutzer.
Abgesehen von diesen Beispielen ist es elegant, ein Skript in Python auszuführen, indem man einfach ein paar magische Variablen einrichtet und das Skript importiert. Das "Ausführen" des Skripts ist ein Nebeneffekt des Imports des Skriptmoduls.
Frage: Kann ich mehrere __name__
Blöcke kontrollieren? Antwort: Es ist seltsam, dies zu tun, aber die Sprache wird Sie nicht daran hindern.
Angenommen, das Folgende ist in foo2.py
. Was passiert, wenn Sie sagen python foo2.py
auf der Kommandozeile? Warum?
import os, sys; sys.path.insert(0, os.path.dirname(file)) # needed for some interpreters
def functionA(): print("a1") from foo2 import functionB print("a2") functionB() print("a3")
def functionB(): print("b")
print("t1") if name == "main": print("m1") functionA() print("m2") print("t2")
Finden Sie nun heraus, was passiert, wenn Sie die __name__
einchecken foo3.py
:
import os, sys; sys.path.insert(0, os.path.dirname(file)) # needed for some interpreters
def functionA(): print("a1") from foo3 import functionB print("a2") functionB() print("a3")
def functionB(): print("b")
print("t1") print("m1") functionA() print("m2") print("t2")
Was bewirkt dies, wenn es als Skript verwendet wird? Wenn es als Modul importiert wird?
name = "main"
def bar(): print("bar")
print("before name guard") if name == "main": bar() print("after name guard")
Nur aus Neugierde: Was passiert, wenn ich subprocess.run('foo_bar.py')
in einem Python-Skript? Ich nehme an, dass foo_bar
wird gestartet mit __name__ = '__main__'
genau wie beim Tippen foo_bar.py
in cmd manuell. Ist das der Fall? Unter Berücksichtigung von @MrFooz' Antwort sollte es kein Problem sein, dies zu tun und so viele "Haupt"-Module auf einmal zu haben, wie ich möchte. Auch das Ändern der __name__
Wertes oder mit mehreren unabhängig voneinander erstellten Instanzen (oder Instanzen, die sich gegenseitig durch subprocess
) miteinander interagieren, sollte für Python eine Selbstverständlichkeit sein. Vermisse ich etwas?
@hajef Sie haben Recht, wie die Dinge mit subprocess.run
. Abgesehen davon ist es im Allgemeinen besser, Code zwischen Skripten zu teilen, indem man Module erstellt und die Skripte die gemeinsamen Module aufrufen lässt, anstatt sich gegenseitig als Skripte aufzurufen. Es ist schwer zu debuggen subprocess.run
Da die meisten Debugger nicht über Prozessgrenzen hinweg springen, kann es einen nicht-trivialen System-Overhead verursachen, um die zusätzlichen Prozesse zu erzeugen und zu zerstören, usw.
Ich habe eine Frage zum Beispiel von foo2.py im Abschnitt "Denkanstöße". Was bedeutet from foo2.py import functionB? Meiner Meinung nach importiert es einfach foo2.py von functionB
Wenn Ihr Skript ausgeführt wird, indem Sie es als Befehl an den Python-Interpreter übergeben,
python myscript.py
wird der gesamte Code, der sich auf der Einrückungsebene 0 befindet, ausgeführt. Funktionen und Klassen, die definiert sind, sind auch definiert, aber keiner ihrer Codes wird ausgeführt. Im Gegensatz zu anderen Sprachen gibt es keine main()
Funktion, die automatisch ausgeführt wird - die main()
Funktion ist implizit der gesamte Code auf der obersten Ebene.
In diesem Fall ist der Top-Level-Code ein if
Block. __name__
ist eine eingebaute Variable, die den Namen des aktuellen Moduls auswertet. Wenn jedoch ein Modul direkt ausgeführt wird (wie in myscript.py
oben), dann __name__
wird stattdessen auf die Zeichenkette "__main__"
. Sie können also testen, ob Ihr Skript direkt ausgeführt wird oder von etwas anderem importiert wird, indem Sie Folgendes testen
if __name__ == "__main__":
...
Wenn Ihr Skript in ein anderes Modul importiert wird, werden seine verschiedenen Funktions- und Klassendefinitionen importiert und sein Top-Level-Code wird ausgeführt, aber der Code im then-body der if
Klausel wird nicht ausgeführt, da die Bedingung nicht erfüllt ist. Betrachten Sie als einfaches Beispiel die folgenden beiden Skripte:
# file one.py
def func():
print("func() in one.py")
print("top-level in one.py")
if __name__ == "__main__":
print("one.py is being run directly")
else:
print("one.py is being imported into another module")
# file two.py
import one
print("top-level in two.py")
one.func()
if __name__ == "__main__":
print("two.py is being run directly")
else:
print("two.py is being imported into another module")
Wenn Sie nun den Interpreter als
python one.py
Die Ausgabe wird sein
top-level in one.py
one.py is being run directly
Wenn Sie two.py
stattdessen:
python two.py
Sie erhalten
top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly
Wenn also das Modul one
geladen wird, seine __name__
ist gleich "one"
代わりに "__main__"
.
Así que, if __name__ == "__main__":
prüft im Grunde, ob Sie Ihr Python-Skript selbst ausführen und es nicht importieren oder so?
Die einfachste Erklärung für die __name__
Variable (imho) ist die folgende:
Erstellen Sie die folgenden Dateien.
# a.py
import b
und
# b.py
print "Hello World from %s!" % __name__
if __name__ == '__main__':
print "Hello World again from %s!" % __name__
Wenn Sie sie ausführen, erhalten Sie diese Ausgabe:
$ python a.py
Hello World from b!
Wie Sie sehen können, setzt Python beim Import eines Moduls globals()['__name__']
in diesem Modul auf den Namen des Moduls. Außerdem wird beim Import der gesamte Code des Moduls ausgeführt. Da die if
Anweisung wird ausgewertet zu False
wird dieser Teil nicht ausgeführt.
$ python b.py
Hello World from __main__!
Hello World again from __main__!
Wie Sie sehen können, setzt Python bei der Ausführung einer Datei globals()['__name__']
in dieser Datei auf "__main__"
. Dieses Mal ist die if
Anweisung wird ausgewertet zu True
und wird ausgeführt.
Was bedeutet die
if __name__ == "__main__":
tun?
Um die Grundlagen zu skizzieren:
Die globale Variable, __name__
in dem Modul, das den Einstiegspunkt in Ihr Programm bildet, ist '__main__'
. Ansonsten ist es der Name, unter dem Sie das Modul importieren.
Also, Code unter der if
Block wird nur ausgeführt, wenn das Modul der Einstiegspunkt in Ihr Programm ist.
Er ermöglicht es, dass der Code im Modul von anderen Modulen importiert werden kann, ohne dass der darunter liegende Codeblock beim Import ausgeführt wird.
Warum brauchen wir das?
Angenommen, Sie schreiben ein Python-Skript, das als Modul verwendet werden soll:
def do_important():
"""This function does something very important"""
Sie könnte Testen Sie das Modul, indem Sie diesen Funktionsaufruf unten anhängen:
do_important()
und führen Sie es (in einer Eingabeaufforderung) mit etwas wie:
~$ python important.py
Wenn Sie das Modul jedoch in ein anderes Skript importieren möchten:
import important
Beim Import wird die do_important
Funktion aufgerufen werden würde, also würden Sie wahrscheinlich Ihren Funktionsaufruf auskommentieren, do_important()
am unteren Rand.
# do_important() # I must remember to uncomment to execute this!
Und dann müssen Sie sich merken, ob Sie den Aufruf der Testfunktion auskommentiert haben oder nicht. Und diese zusätzliche Komplexität würde bedeuten, dass Sie es wahrscheinlich vergessen werden, was Ihren Entwicklungsprozess noch mühsamer macht.
Le site __name__
verweist auf den Namespace, in dem sich der Python-Interpreter im Moment befindet.
Innerhalb eines importierten Moduls ist es der Name des Moduls.
Aber innerhalb des primären Moduls (oder einer interaktiven Python-Sitzung, d.h. der Read-, Eval-, Print-Schleife oder REPL des Interpreters) führen Sie alles von dessen "__main__"
.
Wenn Sie also vor der Ausführung prüfen:
if __name__ == "__main__":
do_important()
Auf diese Weise wird Ihr Code nur ausgeführt, wenn Sie ihn als primäres Modul ausführen (oder ihn absichtlich von einem anderen Skript aus aufrufen).
Es gibt jedoch einen pythonischen Weg, dies zu verbessern.
Was ist, wenn wir diesen Geschäftsprozess von außerhalb des Moduls ausführen wollen?
Wenn wir den Code, den wir beim Entwickeln und Testen üben wollen, in eine Funktion wie diese einfügen und dann unsere Prüfung auf '__main__'
unmittelbar danach:
def main():
"""business logic for when running this module as the primary one!"""
setup()
foo = do_important()
bar = do_even_more_important(foo)
for baz in bar:
do_super_important(baz)
teardown()
# Here's our payoff idiom!
if __name__ == '__main__':
main()
Wir haben jetzt eine letzte Funktion für das Ende unseres Moduls, die ausgeführt wird, wenn wir das Modul als primäres Modul ausführen.
Damit können das Modul und seine Funktionen und Klassen in andere Skripte importiert werden, ohne dass die main
Funktion und ermöglicht auch den Aufruf des Moduls (und seiner Funktionen und Klassen), wenn es von einem anderen '__main__'
Modul, d.h.
import important
important.main()
Dieses Idiom findet sich auch in der Python-Dokumentation in einer Erklärung der __main__
Modul. In diesem Text heißt es:
Dieses Modul stellt den (ansonsten anonymen) Bereich dar, in dem die Hauptprogramm des Interpreters ausgeführt wird - Befehle, die entweder von Standardeingabe, aus einer Skriptdatei oder von einer interaktiven Eingabeaufforderung. Es ist diese Umgebung, in der die idiomatische "bedingte Skript"-Strophe die Ausführung eines Skripts veranlasst:
if __name__ == '__main__': main()
Es tut mir leid, aber ich kann keinen Unterschied zwischen der Methode, die in dem Abschnitt A Better Way
und die Methode, die im Abschnitt An Even Better Way
. Könnten Sie bitte darauf hinweisen?
Warum braucht eine Datei helloworld.py
mit nur print("hello world")
kann mit dem Befehl python helloworld.py
auch wenn es keine if __name__ == "__main__"
?
Wenn Sie python helloworld.py
wird die gesamte Skriptdatei ausgeführt (unabhängig davon, ob Sie if __name__ == "__main__"
oder nicht ) . Es gibt nur einen Unterschied in der Ausführung, wenn Sie importieren helloworld.py
aus einem anderen Skript. In diesem Fall wird die if __name__ == "__main__"
wird der Codeblock überhaupt nicht ausgeführt.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
34 Stimmen
Nur fürs Protokoll - was ist " Haupt ": docs.python.org/3/reference/ und was ist " Name ": docs.python.org/3/reference/