Kiedy pliki .pyc są odświeżane?

92

Rozumiem, że pliki „.pyc” to skompilowane wersje zwykłych plików „.py”, tworzone w czasie wykonywania, aby programy działały szybciej. Zauważyłem jednak kilka rzeczy:

  1. Po modyfikacji plików „py” zachowanie programu zmienia się. Oznacza to, że pliki „py” są kompilowane lub przynajmniej przechodzą przez jakiś proces haszowania lub porównują znaczniki czasu w celu stwierdzenia, czy powinny zostać ponownie skompilowane.
  2. Po usunięciu wszystkich plików „.pyc” ( rm *.pyc) czasami zmienia się zachowanie programu. Co oznaczałoby, że nie są one kompilowane przy aktualizacji plików „.py”.

Pytania:

  • Jak decydują, kiedy mają być kompilowane?
  • Czy istnieje sposób, aby zapewnić dokładniejsze sprawdzanie podczas opracowywania?
Aaron Schif
źródło
15
Uważaj na usuwanie plików .pyc z rozszerzeniem rm *.pyc. Nie spowoduje to usunięcia plików .pyc w zagnieżdżonych folderach. Użyj find . -name '*.pyc' -deletezamiast tego
Zags
6
Może jedna uwaga na Twoje pytanie: program nie działa szybciej, gdy jest czytany z pliku „.pyc” lub „.pyo”, niż gdy jest czytany z pliku „.py”; jedyną szybszą rzeczą w plikach „.pyc” lub „.pyo” jest szybkość, z jaką są ładowane. link
maggie
@maggie jaka jest różnica między czasem ładowania a czasem wykonania?
Daniel Springer
3
@Dani ładowanie to czas potrzebny na odczytanie, a następnie skompilowanie programu. Czas wykonania to czas, w którym program jest faktycznie uruchamiany, co ma miejsce po załadowaniu. Jeśli chcesz być techniczny, typy czasu to czas ładowania, czas kompilacji, czas łącza i czas wykonania. Tworzenie pliku .pyc eliminuje część czasu kompilacji.
Eric Klien
@EricKlien dzięki, stary
Daniel Springer

Odpowiedzi:

81

Te .pycpliki są tworzone (i ewentualnie nadpisane) tylko wtedy, gdy dany plik python jest importowany za pośrednictwem innego skryptu. Jeśli wywoływany jest import, Python sprawdza, czy .pycwewnętrzna sygnatura czasowa pliku nie jest starsza niż odpowiedni .pyplik. Jeśli tak, ładuje .pyc; jeśli tak nie jest lub jeśli .pycjeszcze nie istnieje, Python kompiluje .pyplik do a .pyci ładuje go.

Co masz na myśli mówiąc „ściślejsza kontrola”?

DaveTheScientist
źródło
3
Jestem w stanie rozwiązać problemy z rm *.pyc. Wiem, że jeśli wymuszę odtworzenie wszystkich plików, niektóre problemy zostaną naprawione, co oznacza, że ​​pliki nie są ponownie kompilowane samodzielnie. Przypuszczam, że jeśli używają sygnatur czasowych, nie ma sposobu, aby zaostrzyć to zachowanie, ale problem nadal występuje.
Aaron Schif,
14
To nie jest do końca poprawne. Sygnatury czasowe nie muszą się zgadzać (a zazwyczaj nie). W .pyc„s timestamp musi być starszy niż odpowiadająca .py” s datownika do wyzwolenia rekompilacji.
Tim Pietzcker,
4
@Aaron, Czy prawdopodobnie zmieniasz pliki .py, a tym samym starasz się je postarzać (np. Kopiując je z innego katalogu, używając operacji, która zachowuje „czas modyfikacji”)?
greggo,
1
@greggo, używam git i aktualizuję z repozytorium, więc tak, w pewnym sensie. To mogłoby to zrobić. Dzięki.
Aaron Schif,
1
Dobrze wiedzieć. A co powiesz na poprawienie odpowiedzi?
Piotr Dobrogost
30

Pliki .pyc generowane za każdym razem, gdy odpowiednie elementy kodu są importowane i aktualizowane, jeśli odpowiednie pliki kodu zostały zaktualizowane. Jeśli pliki .pyc zostaną usunięte, zostaną automatycznie wygenerowane ponownie. Jednak nie są one automatycznie usuwane po usunięciu odpowiednich plików kodu.

Może to powodować naprawdę zabawne błędy podczas refaktorów na poziomie plików.

Po pierwsze, możesz skończyć z wypychaniem kodu, który działa tylko na twoim komputerze i na nikim innym. Jeśli masz wiszące odniesienia do usuniętych plików, będą one nadal działać lokalnie, jeśli nie usuniesz ręcznie odpowiednich plików .pyc, ponieważ pliki .pyc mogą być używane podczas importowania. Jest to potęgowane faktem, że odpowiednio skonfigurowany system kontroli wersji będzie przesyłać tylko pliki .py do centralnego repozytorium, a nie pliki .pyc, co oznacza, że ​​Twój kod może przejść „test importu” (czy wszystko jest poprawnie importowane) po prostu dobrze i nie pracować na komputerze innej osoby.

Po drugie, możesz mieć całkiem okropne błędy, jeśli zamienisz pakiety w moduły. Gdy konwertujesz pakiet (folder z __init__.pyplikiem) na moduł (plik .py), pliki .pyc, które kiedyś reprezentowały ten pakiet, pozostają. W szczególności __init__.pycszczątki. Tak więc, jeśli masz pakiet foo z jakimś kodem, który nie ma znaczenia, później usuń ten pakiet i utwórz plik foo.py z jakąś funkcją def bar(): passi uruchom:

from foo import bar

dostajesz:

ImportError: cannot import name bar

ponieważ python nadal używa starych plików .pyc z pakietu foo, z których żaden nie definiuje bar. Może to być szczególnie problematyczne na serwerze internetowym, gdzie całkowicie działający kod może się zepsuć z powodu plików .pyc.

W wyniku obu tych powodów (i być może innych) kod wdrożenia i kod testowy powinny usunąć pliki .pyc, takie jak następujący wiersz bash:

find . -name '*.pyc' -delete

Ponadto, począwszy od pythona 2.6, możesz uruchomić Pythona z -Bflagą, aby nie używać plików .pyc. Zobacz Jak unikać plików .pyc? po więcej szczegółów.

Zobacz też: Jak usunąć wszystkie pliki .pyc z projektu?

Zags
źródło
„Kiedy konwertujesz moduł (folder z __init__.pyplikiem) ...”. To byłby pakiet, a nie moduł.
Robert David Grant
2
W szczególności __init__.pycszczątki. - Dlaczego? Ponieważ pakiet jest katalogiem, usunięcie pakietu oznacza usunięcie katalogu, więc nie ma już plików…
Piotr Dobrogost
3
@PiotrDobrogost Prawidłowo zarządzana kontrola źródła obejmuje nieprzeprowadzanie plików pyc do źródła. Więc chociaż możesz usunąć folder, w tym pliki pyc, w swojej lokalnej kopii, nie zostanie on usunięty przez kogoś, kto wykonuje git pull. Może to spowodować awarię serwera, jeśli wdrożenie obejmuje również git pull.
Zags,
Istnieje wiele powodów, dla których nie można ufać środowisku deweloperskiemu jako reprezentatywnemu dla miejsca, w którym zostanie wdrożony kod. Ten .pycproblem jest również jednym z powodów: ukryte zależności od poziomów poprawek systemu operacyjnego i narzędzi, .soplików , plików konfiguracyjnych, innych bibliotek Pythona (jeśli nie korzystasz z wirtualnego środowiska env), niejasne zmienne env ... lista jest długa. Aby być dokładnym i znaleźć wszystkie takie problemy, musisz zrobić czystą kopię swojego kodu w repozytorium git lub opublikować jako pakiet na serwerze w stylu PyPi i wykonać pełny klon lub konfigurację na nowej maszynie wirtualnej. Niektóre z tych potencjalnych problemów sprawiają, że ten .pycproblem jest blady w porównaniu.
Chris Johnson,