Wann werden .pyc-Dateien aktualisiert?

91

Ich verstehe, dass ".pyc" -Dateien kompilierte Versionen der Klartext ".py" -Dateien sind, die zur Laufzeit erstellt wurden, um die Ausführung von Programmen zu beschleunigen. Ich habe jedoch einige Dinge beobachtet:

  1. Beim Ändern von "py" -Dateien ändert sich das Programmverhalten. Dies zeigt an, dass die "py" -Dateien kompiliert werden oder zumindest einen Hashing-Prozess durchlaufen oder Zeitstempel vergleichen, um festzustellen, ob sie neu kompiliert werden sollen oder nicht.
  2. Beim Löschen aller ".pyc" -Dateien ( rm *.pyc) ändert sich manchmal das Programmverhalten. Was darauf hinweisen würde, dass sie beim Update von ".py" nicht kompiliert werden.

Fragen:

  • Wie entscheiden sie, wann sie kompiliert werden sollen?
  • Gibt es eine Möglichkeit, um sicherzustellen, dass sie während der Entwicklung strenger überprüft werden?
Aaron Schif
quelle
14
Achten Sie darauf, dass Sie keine .pyc-Dateien mit löschen rm *.pyc. Dadurch werden keine .pyc-Dateien in verschachtelten Ordnern gelöscht. Verwenden Sie find . -name '*.pyc' -deletestattdessen
Zags
6
Vielleicht ein Hinweis zu Ihrer Frage: Ein Programm wird beim Lesen aus einer '.pyc'- oder' .pyo'-Datei nicht schneller ausgeführt als beim Lesen aus einer '.py'-Datei. Das einzige, was bei '.pyc'- oder' .pyo'-Dateien schneller ist, ist die Geschwindigkeit, mit der sie geladen werden. Link
Maggie
@maggie was ist der Unterschied zwischen Lade- und Ausführungszeit?
Daniel Springer
3
@Dani Laden ist die Zeit, die benötigt wird, um das Programm zu lesen und dann zu kompilieren. Die Ausführungszeit ist, wenn das Programm tatsächlich ausgeführt wird, was nach dem Laden geschieht. Wenn Sie technisch sein möchten, sind die Zeittypen Ladezeit, Kompilierungszeit, Verknüpfungszeit und Ausführungszeit. Durch das Erstellen eines .pyc entfällt der Kompilierungszeitteil.
Eric Klien
@ EricKlien danke Mann
Daniel Springer

Antworten:

78

Die .pycDateien werden nur erstellt (und möglicherweise überschrieben), wenn diese Python-Datei von einem anderen Skript importiert wird. Wenn der Import aufgerufen wird, prüft Python, ob der .pycinterne Zeitstempel der Datei nicht älter als die entsprechende .pyDatei ist. Wenn dies der Fall ist, wird das geladen .pyc. Wenn dies nicht der .pycFall ist oder noch nicht vorhanden ist, kompiliert Python die .pyDatei in a .pycund lädt sie.

Was meinst du mit "strengerer Kontrolle"?

DaveTheScientist
quelle
3
Ich kann Probleme mit beheben rm *.pyc. Ich weiß, dass einige Probleme behoben werden, wenn ich erzwinge, dass alle Dateien neu erstellt werden, was darauf hinweist, dass die Dateien nicht selbst neu kompiliert werden. Ich nehme an, wenn sie die Zeitstempel verwenden, gibt es keine Möglichkeit, dieses Verhalten zu verschärfen, aber das Problem besteht weiterhin.
Aaron Schif
13
Das ist nicht ganz richtig. Die Zeitstempel müssen nicht übereinstimmen (und normalerweise auch nicht). Der .pycZeitstempel des 'muss älter sein als der .pyZeitstempel des entsprechenden , um eine Neukompilierung auszulösen.
Tim Pietzcker
4
@Aaron, Ändern Sie möglicherweise die .py-Dateien und machen sie dabei älter (z. B. indem Sie sie aus einem anderen Verzeichnis kopieren und dabei eine Operation verwenden, bei der die Änderungszeit erhalten bleibt)?
Greggo
1
@greggo, ich benutze git und aktualisiere aus einem Repository, also ja in gewisser Weise. Das könnte es schaffen. Vielen Dank.
Aaron Schif
1
Gut zu wissen. Wie wäre es dann mit einer Korrektur Ihrer Antwort?
Piotr Dobrogost
29

.pyc-Dateien werden generiert, wenn die entsprechenden Codeelemente importiert werden, und aktualisiert, wenn die entsprechenden Code-Dateien aktualisiert wurden. Wenn die .pyc-Dateien gelöscht werden, werden sie automatisch neu generiert. Sie werden jedoch nicht automatisch gelöscht, wenn die entsprechenden Codedateien gelöscht werden.

Dies kann einige wirklich lustige Fehler bei Refactors auf Dateiebene verursachen.

Zuallererst können Sie Code pushen, der nur auf Ihrem Computer und auf keinem anderen funktioniert. Wenn Sie Verweise auf gelöschte Dateien haben, funktionieren diese weiterhin lokal, wenn Sie die relevanten .pyc-Dateien nicht manuell löschen, da .pyc-Dateien beim Import verwendet werden können. Dies wird durch die Tatsache verstärkt, dass ein ordnungsgemäß konfiguriertes Versionskontrollsystem nur .py-Dateien in das zentrale Repository überträgt, nicht .pyc-Dateien, was bedeutet, dass Ihr Code den "Importtest" bestehen kann (funktioniert alles in Ordnung), einwandfrei und nicht Arbeit auf dem Computer eines anderen.

Zweitens können einige ziemlich schreckliche Fehler auftreten, wenn Sie Pakete in Module verwandeln. Wenn Sie ein Paket (einen Ordner mit einer __init__.pyDatei) in ein Modul (eine .py-Datei) konvertieren, bleiben die .pyc-Dateien erhalten, die dieses Paket einmal dargestellt haben. Insbesondere die __init__.pycÜberreste. Wenn Sie also das Paket foo mit einem Code haben, der keine Rolle spielt, löschen Sie das Paket später und erstellen Sie eine Datei foo.py mit einer Funktion def bar(): passund führen Sie Folgendes aus:

from foo import bar

du erhältst:

ImportError: cannot import name bar

weil Python immer noch die alten .pyc-Dateien aus dem foo-Paket verwendet, von denen keine die Leiste definiert. Dies kann besonders auf einem Webserver problematisch sein, auf dem vollständig funktionierender Code aufgrund von .pyc-Dateien beschädigt werden kann.

Aus diesen beiden Gründen (und möglicherweise aus anderen Gründen) sollten Ihr Bereitstellungscode und Ihr Testcode .pyc-Dateien löschen, z. B. mit der folgenden Bash-Zeile:

find . -name '*.pyc' -delete

-BAb Python 2.6 können Sie Python auch mit dem Flag ausführen, um keine .pyc-Dateien zu verwenden. Siehe So vermeiden Sie .pyc-Dateien für mehr Details.

Siehe auch: Wie entferne ich alle .pyc-Dateien aus einem Projekt?

Zags
quelle
"Wenn Sie ein Modul (einen Ordner mit einer __init__.pyDatei) konvertieren ...". Das wäre ein Paket, kein Modul.
Robert David Grant
2
Insbesondere die __init__.pycÜberreste. - Woher? Da ein Paket ein Verzeichnis ist, bedeutet das Löschen eines Pakets das Löschen eines Verzeichnisses, sodass keine Dateien mehr vorhanden sind.
Piotr Dobrogost
3
@PiotrDobrogost Bei einer ordnungsgemäß verwalteten Quellcodeverwaltung werden Ihre Pyc-Dateien nicht in den Quellcode eingecheckt. Während Sie den Ordner, einschließlich der Pyc-Dateien, in Ihrer lokalen Kopie löschen können, wird er nicht für eine andere Person gelöscht, die einen Git-Pull ausführt. Dies kann Ihren Server zum Absturz bringen, wenn Ihre Bereitstellung auch einen Git-Pull beinhaltet.
Zags
Es gibt viele Gründe, nicht darauf zu vertrauen, dass Ihre Entwicklungsumgebung repräsentativ dafür ist, wo Ihr Code bereitgestellt wird. Dieses .pycProblem ist auch ein Grund: versteckte Abhängigkeiten von Betriebssystem- und Dienstprogramm-Patch-Levels, .soDateien, Konfigurationsdateien, anderen Python-Bibliotheken (wenn Sie nicht in einer virtuellen Umgebung ausgeführt werden), obskure Umgebungsvariablen ... die Liste geht weiter. Um gründlich zu sein und all diese Probleme zu finden, müssen Sie eine saubere Kopie Ihres Codes in einem Git-Repo erstellen oder als Paket auf einem PyPi-Server veröffentlichen und einen vollständigen Klon oder ein Setup auf einer neuen VM durchführen. Einige dieser potenziellen Probleme machen dieses .pycProblem im Vergleich blass.
Chris Johnson