539 Stimmen

Was ist __main__.py?

Was ist die __main__.py Datei zu erstellen, welche Art von Code sollte ich darin eingeben und wann sollte ich eine Datei erstellen?

496voto

Ned Batchelder Punkte 342778

Oft wird ein Python-Programm ausgeführt, indem man eine .py-Datei auf der Befehlszeile angibt:

$ python my_program.py

Sie können auch ein Verzeichnis oder eine Zip-Datei mit Code erstellen und eine __main__.py . Dann können Sie einfach den Namen des Verzeichnisses oder der Zip-Datei in der Befehlszeile eingeben, und das Programm führt die __main__.py automatisch:

$ python my_program_dir
$ python my_program.zip
# Or, if the program is accessible as a module
$ python -m my_program

Sie müssen selbst entscheiden, ob Ihre Anwendung von einer solchen Ausführung profitieren könnte.


Beachten Sie, dass eine __main__ Modul kommt normalerweise nicht von einer __main__.py Datei. Das ist möglich, aber normalerweise nicht der Fall. Wenn Sie ein Skript wie python my_program.py wird das Skript als __main__ Modul anstelle des my_program Modul. Dies geschieht auch bei Modulen, die als python -m my_module oder auf verschiedene andere Weise.

Wenn Sie den Namen __main__ in einer Fehlermeldung auftaucht, bedeutet das nicht unbedingt, dass Sie nach einem Fehler suchen sollten. __main__.py archivo.

204voto

Was ist die __main__.py Datei für?

Bei der Erstellung eines Python-Moduls ist es üblich, dass das Modul eine bestimmte Funktionalität ausführt (die normalerweise in einer main Funktion), wenn sie als Einstiegspunkt des Programms ausgeführt wird. Dies wird typischerweise mit dem folgenden gemeinsamen Idiom am Ende der meisten Python-Dateien gemacht:

if __name__ == '__main__':
    # execute only if run as the entry point into the program
    main()

Sie können die gleiche Semantik für ein Python-Paket mit __main__.py die die folgende Struktur haben könnte:

.
 demo
     __init__.py
     __main__.py

Um dies zu sehen, fügen Sie den folgenden Text in eine Python 3-Shell ein:

from pathlib import Path

demo = Path.cwd() / 'demo'
demo.mkdir()

(demo / '__init__.py').write_text("""
print('demo/__init__.py executed')

def main():
    print('main() executed')
""")

(demo / '__main__.py').write_text("""
print('demo/__main__.py executed')

from demo import main

main()
""")

Wir können Demo als ein Paket behandeln und es tatsächlich importieren, was den Top-Level-Code in der __init__.py (aber nicht die main Funktion):

>>> import demo
demo/__init__.py executed

Wenn wir das Paket als Einstiegspunkt für das Programm verwenden, führen wir den Code in der __main__.py die die __init__.py Erstens:

$ python -m demo
demo/__init__.py executed
demo/__main__.py executed
main() executed

Sie können dies aus der Dokumentation entnehmen. Die Dokumentation dit :

__main__ - Skriptumgebung der obersten Ebene

'__main__' ist der Name des Bereichs, in dem der Code der obersten Ebene ausgeführt wird. Der Bereich eines Moduls __name__ gleichgesetzt wird mit '__main__' beim Lesen von Standard Eingabe, einem Skript oder von einer interaktiven Eingabeaufforderung gelesen wird.

Ein Modul kann feststellen, ob es im Hauptbereich läuft oder nicht läuft, indem es seine eigene __name__ die ein gemeinsames Idiom ermöglicht für bedingte Ausführung von Code in einem Modul, wenn es als Skript oder mit python -m aber nicht, wenn es importiert wird:

if __name__ == '__main__':
     # execute only if run as a script
     main()

Bei einem Paket kann derselbe Effekt erzielt werden, indem eine __main__.py Modul, dessen Inhalt ausgeführt wird, wenn das Modul mit -m .

Mit Reißverschluss

Sie können dieses Verzeichnis auch komprimieren, einschließlich der __main__.py in eine einzige Datei packen und von der Kommandozeile aus wie folgt ausführen - beachten Sie jedoch, dass gepackte Pakete keine Unterpakete oder Untermodule als Einstiegspunkt ausführen können:

from pathlib import Path

demo = Path.cwd() / 'demo2'
demo.mkdir()

(demo / '__init__.py').write_text("""
print('demo2/__init__.py executed')

def main():
    print('main() executed')
""")

(demo / '__main__.py').write_text("""
print('demo2/__main__.py executed')

from __init__ import main

main()
""")

Beachten Sie die subtile Änderung - wir importieren main de __init__ 代わりに demo2 - dieses gezippte Verzeichnis wird nicht als Paket, sondern als Verzeichnis mit Skripten behandelt. Daher muss es ohne das -m Flagge.

Besonders relevant für die Frage - zipapp veranlasst das gezippte Verzeichnis, die __main__.py standardmäßig - und sie wird zuerst ausgeführt, bevor __init__.py :

$ python -m zipapp demo2 -o demo2zip
$ python demo2zip
demo2/__main__.py executed
demo2/__init__.py executed
main() executed

Nochmals: Dieses gezippte Verzeichnis ist kein Paket - Sie können es auch nicht importieren.

55voto

Tasos Papastylianou Punkte 20016

Einige der Antworten hier implizieren, dass ein "Paket"-Verzeichnis (mit oder ohne explizite __init__.py Datei), die eine __main__.py Datei, gibt es keinen Unterschied zwischen der Ausführung dieses Verzeichnisses mit dem -m Schalter oder ohne.

Der große Unterschied besteht darin, dass ohne el -m Schalter, das Verzeichnis "package" wird zunächst dem Pfad hinzugefügt (d.h. sys.path), und dann werden die Dateien normal ausgeführt, ohne Paketsemantik .

. mit el -m Schalter, die Semantik der Pakete (einschließlich relativer Importe) wird beachtet und das Paketverzeichnis selbst wird nie zum Systempfad hinzugefügt .

Dies ist eine sehr wichtige Unterscheidung, sowohl in Bezug auf die Frage, ob relative Importe funktionieren oder nicht, als auch, was noch wichtiger ist, in Bezug auf das Diktat der was im Falle einer unbeabsichtigten Verschattung von Systemmodulen importiert wird .


Beispiel:

Nehmen wir ein Verzeichnis namens PkgTest mit der folgenden Struktur

:~/PkgTest$ tree
.
 pkgname
    __main__.py
    secondtest.py
    testmodule.py
 testmodule.py

wo die __main__.py hat den folgenden Inhalt:

:~/PkgTest$ cat pkgname/__main__.py
import os
print( "Hello from pkgname.__main__.py. I am the file", os.path.abspath( __file__ ) )
print( "I am being accessed from", os.path.abspath( os.curdir ) )
from  testmodule import main as firstmain;     firstmain()
from .secondtest import main as secondmain;    secondmain()

(wobei die anderen Dateien in ähnlicher Weise definiert sind und ähnliche Ausdrucke aufweisen).

Wenn Sie dies ohne die -m wechseln, erhalten Sie Folgendes. Beachten Sie, dass der relative Import fehlschlägt, aber was noch wichtiger ist, beachten Sie, dass das falsche Testmodul ausgewählt wurde (d.h. relativ zum Arbeitsverzeichnis):

:~/PkgTest$ python3 pkgname
Hello from pkgname.__main__.py. I am the file ~/PkgTest/pkgname/__main__.py
I am being accessed from ~/PkgTest
Hello from testmodule.py. I am the file ~/PkgTest/pkgname/testmodule.py
I am being accessed from ~/PkgTest
Traceback (most recent call last):
  File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "pkgname/__main__.py", line 10, in <module>
    from .secondtest import main as secondmain
ImportError: attempted relative import with no known parent package

Mit der Option -m hingegen erhalten Sie das, was Sie (hoffentlich) erwartet haben:

:~/PkgTest$ python3 -m pkgname
Hello from pkgname.__main__.py. I am the file ~/PkgTest/pkgname/__main__.py
I am being accessed from ~/PkgTest
Hello from testmodule.py. I am the file ~/PkgTest/testmodule.py
I am being accessed from ~/PkgTest
Hello from secondtest.py. I am the file ~/PkgTest/pkgname/secondtest.py
I am being accessed from ~/PkgTest


Anmerkung: Meiner ehrlichen Meinung nach ist das Laufen ohne -m sollten vermieden werden. Ich würde sogar noch weiter gehen und sagen, dass ich jede executable packages so, dass sie fehlschlagen würden, wenn sie nicht über den -m Schalter.

Mit anderen Worten, ich würde nur von "In-Package"-Modulen explizit über "relative Importe" importieren, in der Annahme, dass alle anderen Importe Systemmodule darstellen. Wenn jemand versucht, Ihr Paket ohne die -m werden die relativen Import-Anweisungen einen Fehler auslösen, anstatt das falsche Modul stillschweigend auszuführen.

41voto

anatoly techtonik Punkte 18578

Sie erstellen __main__.py en yourpackage um es als ausführbar zu machen:

$ python -m yourpackage

38voto

Blue Peppers Punkte 3532

__main__.py wird für Python-Programme in Zip-Dateien verwendet. Die __main__.py Datei wird ausgeführt, wenn die Zip-Datei ausgeführt wird. Zum Beispiel, wenn die Zip-Datei war als solche:

test.zip
     __main__.py

und der Inhalt von __main__.py war

import sys
print "hello %s" % sys.argv[1]

Wenn wir dann die python test.zip world würden wir hello world aus.

Also die __main__.py Datei ausgeführt, wenn Python für eine Zip-Datei aufgerufen wird.

CodeJaeger.com

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.

Powered by:

X