Warum funktioniert die Python Module kompilieren, aber nicht das Skript ausgeführt wird?
Warum Python kompilieren Bibliotheken, die verwendet werden, in einem Skript, aber nicht das Skript aufgerufen wird, selbst?
Beispielsweise
Wenn es main.py
und module.py
, und Python ist laufen by doing python main.py
wird es eine kompilierte Datei module.pyc
aber nicht der wichtigste. Warum?
Bearbeiten
Hinzufügen der bounty. Ich glaube nicht, dass dies zufriedenstellend beantwortet wurde.
-
Wenn die Antwort ist möglichen Datenträger-Berechtigungen für das Verzeichnis der
main.py
, warum Python-Module kompilieren? Sie sind genauso wahrscheinlich (wenn nicht wahrscheinlicher) erscheint in einer Lage, wo der Benutzer keinen Schreibzugriff haben. Python kompilieren könntemain
wenn es beschreibbar ist, oder alternativ in ein anderes Verzeichnis. -
Wenn der Grund ist, dass der nutzen minimal sein wird, betrachten Sie die situation, wenn das Skript verwendet eine große Anzahl von Zeiten (z.B. in einem CGI-Anwendung).
- Wäre ich +1 auf der basis der Fragen eine interessante Frage, aber ich bin eigentlich -1 ausgewählt, weil Sie eine falsche Antwort.
- Was ist die richtige Antwort in Ihrem Blick?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dateien kompiliert werden, bei der Einfuhr. Es ist nicht eine Sicherheits-Sache. Es ist einfach so, dass, wenn Sie es importieren python speichert die Ausgabe. Sehen dieser Beitrag von Fredrik Lundh auf Effbot.
Beim ausführen eines python-Skript wird nicht verwenden Sie die *.pyc-Datei.
Wenn Sie einige andere Grund, warum Sie wollen, dass Ihr Skript vorkompiliert können Sie die
compileall
Modul.compileall Nutzung
Antworten auf Frage Bearbeiten
Module und Skripte werden gleich behandelt. Importieren ist, was löst die Ausgabe gespeichert werden soll.
Mit compileall löst dieses Problem nicht.
Skripte ausgeführt, die von python wird nicht die
*.pyc
sofern nicht ausdrücklich genannt. Dies hat negative Nebenwirkungen, gut erklärt von Glenn Maynard in seine Antwort.Beispiel einer CGI-Anwendung sollte wirklich angegangen werden, indem eine Technik wie FastCGI. Wenn Sie ausschließen wollen, dass der Aufwand kompilieren Sie Ihr Skript möglicherweise möchten Sie eliminieren den Aufwand der Inbetriebnahme python auch nicht zu erwähnen, Datenbank-Verbindung overhead.
Einem Licht, sein bootstrap-Skript verwendet werden können oder sogar
python -c "import script"
, aber diese fragwürdigen Stil.Glenn Maynard einige inspiration zu korrigieren und verbessern diese Antwort.
"import __main__"
und noch eine .pyc-Datei nicht aus, so dass Behauptung ist nicht korrekt. Auch__main__
ist kompiliert. Das Ergebnis der Kompilation ist nicht nur geschrieben wie ein .pyc-Datei. Es ist nur im ram gehalten wird.Niemand scheint sagen zu wollen, aber ich bin mir ziemlich sicher, die Antwort ist einfach: es gibt keinen festen Grund für dieses Verhalten.
All den Gründen, die so weit sind im wesentlichen falsch:
sys.modules
wie jedes andere Modul. Läuft ein script ist nichts anderes als Import von es mit ein Modul namens__main__
.Weiteres Problem zu beachten: wenn Sie laufen
python foo.py
und foo.pyc existiert, es nicht verwendet werden. Sie müssen explizit sagenpython foo.pyc
. Das ist eine sehr schlechte Idee: es bedeutet, dass Python nicht automatisch neu kompilieren .pyc-Datei, wenn es out-of-sync (wegen der .py-Datei ändern), so dass änderungen an den .py-Datei nicht verwendet werden, bis Sie manuell neu kompilieren. Es wird auch scheitern, geradezu mit einem Absturz mit Laufzeitfehler, wenn Sie ein upgrade von Python und dem .pyc-Datei-format nicht mehr kompatibel ist, das passiert regelmäßig. Normalerweise, das ist alles transparent gehandhabt.Müssen Sie sich nicht bewegen, ein Skript in ein dummy-Modul und set-up-bootstrapping-Skript trick Python in Zwischenspeichern es. Das ist ein hackish Abhilfe.
Nur möglich (und sehr überzeugend) Grund kann ich verstehen es ist zu vermeiden, dass Ihr home-Verzeichnis wird überhäuft mit einem Haufen .pyc Dateien. (Dies ist nicht ein echter Grund; wenn das war eine wirkliche Sorge dann .pyc Dateien gespeichert werden sollen, die als dotfiles.) Es ist sicher kein Grund, nicht auch ein option, dies zu tun.
Python sollte definitiv in der Lage sein, um cache-Hauptprogramm.
Pädagogik
Ich Liebe und hasse Fragen wie diese auf, SO, weil es eine komplexe Mischung aus emotion, Meinung und gebildete Vermutungen gehen auf und die Menschen beginnen, um schnippisch, und irgendwie jeder verliert den überblick über die aktuellen Fakten und schließlich verliert die ursprüngliche Frage völlig.
Viele technische Fragen auf, SO haben wenigstens eine definitive Antwort (z.B. eine Antwort, die überprüft werden können, indem die Ausführung oder eine Antwort, die zitiert eine maßgebliche Quelle), aber diese "warum" - Fragen haben oft nicht nur eine einzige, definitive Antwort. In meinem Kopf gibt es 2 mögliche Wege, um endgültig beantworten "warum" - Frage in der informatik:
Die zweite Art von Antwort ist schwieriger zu belegen, denn es erfordert immer in den Köpfen der Entwickler, die haben den code geschrieben, vor allem, wenn es keine leicht zu finden, die öffentliche Dokumentation welche erklären, eine bestimmte Entscheidung.
Datum, dieser thread hat 7 Antworten, die sich ausschließlich auf das Lesen konzentrieren die Absicht der Python-Entwickler und dennoch gibt es nur ein Zitat in die Partie. (Und es zitiert einen Abschnitt der Python-Handbuch, das tut nicht Antwort auf die OP-Frage.)
Hier ist mein Versuch der Beantwortung beide von den Seiten der "warum" - Frage zusammen mit Zitaten.
Quellcode
Was sind die Voraussetzungen, dass die trigger-Zusammenstellung ein .pyc? Schauen wir uns der source-code. (Störend, das Python auf GitHub keine release-tags, also werde ich einfach sagen, dass ich freue mich auf
715a6e
.)Es ist vielversprechend code in
import.c:989
imload_source_module()
Funktion. Ich habe schneiden Sie einige Teile hier für die Kürze.pathname
ist der Pfad zu den Modul-und diecpathname
ist der gleiche Pfad, aber mit einem .pyc Dateiendung. Die einzige direkte Logik die Booleschesys.dont_write_bytecode
. Der rest der Logik ist nur Fehlerbehandlung. Also die Antwort, die wir suchen, ist nicht hier, aber wir können zumindest sehen, dass code, der fordert, dies wird in einem .pyc-Datei unter den meisten Standard-Konfigurationen. Dieparse_source_module()
Funktion hat keine wirkliche Relevanz für den Ablauf der Ausführung, aber ich zeige es hier, da komme ich später zurück.Den charakteristischen Aspekt ist hier, dass die Funktion parst und kompiliert eine Datei und liefert einen Zeiger auf den byte-code (sofern erfolgreich).
Jetzt sind wir immer noch in einer Sackgasse, so lassen Sie uns dieses Konzept aus einem neuen Blickwinkel. Wie funktioniert Python-laden ist es argument und führen Sie es aus? In
pythonrun.c
es gibt ein paar Funktionen für das laden von code aus einer Datei suchen und ausführen.PyRun_AnyFileExFlags()
behandeln können sowohl interaktive und nicht-interaktive, Datei-Deskriptoren. Für die interaktive Datei-Deskriptoren, delegiert er anPyRun_InteractiveLoopFlags()
(dies ist der REPL) und für nicht-interaktive, Datei-Deskriptoren, delegiert er anPyRun_SimpleFileExFlags()
.PyRun_SimpleFileExFlags()
prüft, ob der Dateiname endet in.pyc
. Wenn es funktioniert, dann ruft esrun_pyc_file()
die direkt Lasten kompilierte byte-code aus einer Datei-Deskriptor und dann läuft es.In der mehr Allgemeinen Fall (d.h.
.py
- Datei als argument),PyRun_SimpleFileExFlags()
AnrufePyRun_FileExFlags()
. Dies ist, wo wir beginnen, finden Sie unsere Antwort.Der springende Punkt hier ist, dass diese beiden Funktionen im wesentlichen den gleichen Zweck wie der Importeur
load_source_module()
undparse_source_module()
. Er ruft den parser zu erstellen, der eine AST aus Python-Quellcode und ruft dann erstellt der compiler byte-code.So werden diese code-Blöcke redundant oder machen Sie anderen Zwecken dienen? Der Unterschied ist, dass ein block lädt ein Modul aus einer Datei, während der andere block dauert ein Modul als argument. Das Modul argument ist — in diesem Fall — die
__main__
- Modul, welches zuvor erstellt haben in der Initialisierungs-Prozess mit einer low-level C-Funktion. Die__main__
Modul nicht durch die meisten normalen Modul import-code-Pfade, weil es ist so einzigartig, und als Nebeneffekt, es geht nicht über den code, der erzeugt.pyc
- Dateien.Zu fassen: der Grund, warum die
__main__
Modul nicht kompiliert .pyc ist, dass es nicht "importiert" werden. Ja, es erscheint in der sys.Module, aber es wird dort über einen ganz anderen code-Pfad als echtes Modul Einfuhren nehmen.Entwickler Absicht
Okay, so können wir nun sehen, dass das Verhalten hat mehr zu tun mit der Gestaltung von Python als mit jedem klar ausgedrückt Begründung in den Quellcode, aber nicht die Antwort auf die Frage, ob dies eine absichtliche Entscheidung oder nur ein Nebeneffekt, der nicht stört niemanden genug, um Wert zu ändern. Einer der Vorteile von open source ist, dass wir einmal gefunden haben, der Quellcode, die uns interessiert, können wir mit den VCS zu helfen, die Spur zurück zu den Entscheidungen, die led an der derzeitigen Umsetzung.
Einer der zentralen Zeilen code hier (
m = PyImport_AddModule("__main__");
) stammt aus 1990 und wurde geschrieben von der BDFL sich, Guido. Es wurde geändert im Laufe der Jahre, aber die änderungen sind oberflächlich. Wenn es wurde zuerst geschrieben, das main-Modul für ein script argument initialisiert wurde, so:Diese Bestand vor
.pyc
Dateien wurden auch eingeführt in Python! Kein Wunder, dass das design an, dass die Zeit nicht nehmen-Zusammenstellung berücksichtigt, für die Skript-Argumente. Die commit-Nachricht rätselhaft, sagt:Dies war einer von mehreren Dutzend commits, die über eine Frist von 3 Tagen... es scheint, dass Guido war tief in einige hacking/refactoring und dies war die erste version, die zurück kam, um als stabil. Diese verpflichten, sogar älter als die Schöpfung von die Python-Dev-mailing-Liste von über fünf Jahren!
Speichern der kompilierten bytecode war eingeführt 6 Monate später, 1991.
Diese noch vor der Liste dienen, so haben wir keine wirkliche Vorstellung von dem, was Guido denken. Es scheint, dass er einfach dachte, dass der Importeur war der beste Ort, um hook in der zum Zweck der Zwischenspeicherung von Bytecode. Ob er betrachtet die Idee, das gleiche tun für
__main__
ist unklar: entweder es hat nicht auftreten, zu ihm, oder aber er dachte, dass es mehr ärger als es Wert war.Kann ich nicht finden __main__+pyc&submit=suchen&status=-1%2C1%2C2%2C3" >alle bugs auf bugs.python.org im Zusammenhang caching des bytecodes für das main-Modul, noch kann ich Nachrichten auf der mailing-Liste darüber, so dass anscheinend niemand sonst findet es der Mühe Wert, versuchen Sie es.
Zu fassen: der Grund, warum alle Module kompiliert werden, um
.pyc
außer__main__
ist, dass es eine Laune der Geschichte. Das design und die Implementierung für wie__main__
Werk wurde fest in den code vor.pyc
Dateien noch gar nicht existierte. Wenn Sie mehr wissen wollen als die, müssen Sie die e-mail-Guido und Fragen.Glenn Maynard ' s Antwort sagt:
Ich zu 100% Zustimmen. Es gibt Indizien, die diese Theorie unterstützen und sonst niemand in diesem thread hat sich eine einzige Spur der Beweise zu unterstützen jeder anderen Theorie. Ich von Ihnen positiv bewertet werden Glenn ' s Antwort.
Da:
Ist unnötig zu generieren .pyc-Datei für Haupt-Skript. Nur die Bibliotheken, die geladen werden könnten, viele Male übersetzt werden soll.
Bearbeitet:
Scheint es Sie nicht mein Punkt. Erstens, zu wissen, die ganze Idee der Zusammenstellung in
.pyc
- Datei, die gleiche Datei ausführen schneller beim zweiten mal. Bedenken Sie jedoch, wenn Python hast, kompilieren Sie das Skript ausgeführt wird. Der interpreter schreiben-bytecode in eine.pyc
- Datei bei der ersten Ausführung, das braucht Zeit. So wird es sogar ein bisschen langsamer. Man könnte argumentieren, dass es schneller nach. Gut, es ist nur eine Wahl. Plus, wiethis
sagt:Will man eine Beschleunigung durch die Verwendung von
.pyc
- Datei, sollte man kompilieren Sie es manuell, und führen Sie die.pyc
- Datei explizit.Ihre Frage zu beantworten, Verweis auf 6.1.3. "Kompiliert" Python-Dateien in Python offiziellen Dokument.
Weil das Skript ausgeführt werden kann, irgendwo, wo es nicht angebracht ist, zu generieren .pyc Dateien, wie
/usr/bin
.Special cases aren't special enough to break the rules.