Quando vengono aggiornati i file .pyc?


91

Capisco che i file ".pyc" sono versioni compilate dei file ".py" in testo semplice, creati in fase di esecuzione per rendere i programmi più veloci. Tuttavia ho osservato alcune cose:

  1. Dopo la modifica dei file "py", il comportamento del programma cambia. Ciò indica che i file "py" sono compilati o almeno passano attraverso una sorta di processo di hashing o confrontano i timestamp per stabilire se devono essere ricompilati o meno.
  2. Dopo l'eliminazione di tutti i file ".pyc" ( rm *.pyc), a volte il comportamento del programma cambia. Il che indicherebbe che non vengono compilati con l'aggiornamento di ".py".

Domande:

  • Come decidono quando devono essere compilati?
  • C'è un modo per garantire che abbiano controlli più rigorosi durante lo sviluppo?

14
Attenzione a eliminare i file .pyc con rm *.pyc. Ciò non eliminerà i file .pyc nelle cartelle nidificate. Usa find . -name '*.pyc' -deleteinvece
Zags

6
Forse una nota sulla tua domanda: un programma non viene eseguito più velocemente quando viene letto da un file ".pyc" o ".pyo" rispetto a quando viene letto da un file ".py"; l'unica cosa che è più veloce dei file ".pyc" o ".pyo" è la velocità con cui vengono caricati. link
maggie

@maggie qual è la differenza tra il tempo di caricamento e quello di esecuzione?
Daniel Springer

3
Il caricamento di @Dani è il tempo necessario per leggere e quindi compilare il programma. Il tempo di esecuzione è quando il programma viene effettivamente eseguito, il che accade dopo il caricamento. Se vuoi essere tecnico, i tipi di tempo sono tempo di caricamento, tempo di compilazione, tempo di collegamento e tempo di esecuzione. Creare un .pyc elimina la parte del tempo di compilazione.
Eric Klien

@EricKlien ringrazia l'uomo
Daniel Springer,

Risposte:


79

I .pycfile vengono creati (ed eventualmente sovrascritti) solo quando quel file python viene importato da qualche altro script. Se viene chiamata l'importazione, Python verifica se il .pyctimestamp interno del file non è più vecchio del .pyfile corrispondente . Se lo è, carica il .pyc; se non lo è o se .pycnon esiste ancora, Python compila il .pyfile in a .pyce lo carica.

Cosa intendi per "controllo più rigoroso"?


3
Sono in grado di risolvere i problemi con rm *.pyc. So che se forzo la ricreazione di tutti i file, alcuni problemi vengono risolti, indicando che i file non vengono ricompilati da soli. Suppongo che se usano i timestamp, non c'è modo di rendere questo comportamento più rigoroso, ma il problema persiste.
Aaron Schif

13
Questo non è del tutto corretto. I timestamp non devono corrispondere (e di solito no). Il .pyctimestamp di deve essere più vecchio del .pytimestamp del corrispondente per attivare una ricompilazione.
Tim Pietzcker

4
@ Aaron, stai forse cambiando i file .py e nel processo rendendoli più vecchi (ad esempio copiandoli da un'altra directory, usando un'operazione che preserva il "tempo di modifica")?
greggo

1
@greggo, sto usando git e aggiorno da un repository, quindi sì in un certo senso lo sono. Potrebbe farlo. Grazie.
Aaron Schif

1
Buono a sapersi. Che ne dici di correggere la tua risposta allora?
Piotr Dobrogost

29

File .pyc generati ogni volta che vengono importati gli elementi di codice corrispondenti e aggiornati se i file di codice corrispondenti sono stati aggiornati. Se i file .pyc vengono eliminati, verranno automaticamente rigenerati. Tuttavia, essi sono non cancellati automaticamente quando i file di codice corrispondenti vengono eliminati.

Ciò può causare alcuni bug davvero divertenti durante i refactors a livello di file.

Prima di tutto, puoi finire per spingere il codice che funziona solo sulla tua macchina e su quella di nessun altro. Se hai riferimenti penzolanti ai file eliminati, questi continueranno a funzionare localmente se non elimini manualmente i file .pyc pertinenti perché i file .pyc possono essere utilizzati nelle importazioni. Ciò è aggravato dal fatto che un sistema di controllo della versione configurato correttamente invierà solo file .py al repository centrale, non file .pyc, il che significa che il tuo codice può superare il "test di importazione" (importa tutto bene) bene e non lavorare sul computer di qualcun altro.

Secondo, puoi avere dei bug piuttosto terribili se trasformi i pacchetti in moduli. Quando si converte un pacchetto (una cartella con un __init__.pyfile) in un modulo (un file .py), i file .pyc che una volta rappresentavano quel pacchetto rimangono. In particolare, i __init__.pycresti. Quindi, se hai il pacchetto pippo con un codice che non ha importanza, in seguito cancella quel pacchetto e crea un file pippo.py con qualche funzione def bar(): passed esegui:

from foo import bar

ottieni:

ImportError: cannot import name bar

perché python sta ancora usando i vecchi file .pyc dal pacchetto foo, nessuno dei quali definisce bar. Questo può essere particolarmente problematico su un server web, dove il codice completamente funzionante può rompersi a causa dei file .pyc.

Come risultato di entrambi questi motivi (e forse altri), il codice di distribuzione e il codice di test dovrebbero eliminare i file .pyc, ad esempio con la seguente riga di bash:

find . -name '*.pyc' -delete

Inoltre, a partire da python 2.6, puoi eseguire python con il -Bflag per non usare file .pyc. Vedi Come evitare i file .pyc? per ulteriori dettagli.

Vedi anche: Come rimuovo tutti i file .pyc da un progetto?


"Quando converti un modulo (una cartella con un __init__.pyfile) ...". Sarebbe un pacchetto, non un modulo.
Robert David Grant

2
In particolare, i __init__.pycresti. - Come mai? Poiché un pacchetto è una directory, eliminare un pacchetto significa eliminare una directory quindi non ci sono file rimasti ...
Piotr Dobrogost

3
@PiotrDobrogost Il controllo del codice sorgente gestito correttamente implica il mancato controllo dei file pyc nel codice sorgente. Quindi, anche se puoi eliminare la cartella, inclusi i file pyc, nella tua copia locale, non verrà eliminata per qualcun altro che esegue un pull git. Ciò può causare un arresto anomalo del server se la distribuzione prevede anche un pull git.
Zags

Ci sono molte ragioni per non fidarsi del proprio ambiente di sviluppo come rappresentativo di dove verrà distribuito il codice. Questo .pycproblema è anche uno dei motivi: dipendenze nascoste dal sistema operativo e livelli di patch di utilità, .sofile , file di configurazione, altre librerie Python (se non si esegue in un ambiente virtuale), oscure variabili di ambiente ... l'elenco potrebbe continuare. Per essere accurati e trovare tutti questi problemi, è necessario creare una copia pulita del codice in un repository git o pubblicare come pacchetto su un server in stile PyPi ed eseguire un clone completo o una configurazione su una nuova VM. Alcuni di questi potenziali problemi rendono questo .pycproblema pallido al confronto.
Chris Johnson,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.