Se Python viene interpretato, quali sono i file .pyc?


1084

Mi è stato dato di capire che Python è un linguaggio interpretato ...
Tuttavia, quando guardo il mio codice sorgente Python vedo i .pycfile, che Windows identifica come "File Python compilati".

Da dove vengono questi?


3
Vedere stackoverflow.com/questions/11433579/… per una giustificazione. In una parola: velocità.
user7610



Vuol dire che anche Python ha "Scrivi una volta, corri ovunque" proprio come Java.?
Mrak Vladar,

2
@MrakVladar Anche Java è "Scrivi una volta, esegui ovunque [che possiedi una JVM]". Python non è diverso; è "corri ovunque tu abbia una macchina virtuale Python". La grande differenza è che la maggior parte delle implementazioni di Python combinano il compilatore e l'interprete in un eseguibile, anziché separarli come javae javac.
Chepner,

Risposte:


661

Contengono il codice byte , che è quello in cui l'interprete Python compila l'origine. Questo codice viene quindi eseguito dalla macchina virtuale di Python.

La documentazione di Python spiega la definizione in questo modo:

Python è un linguaggio interpretato, al contrario di un linguaggio compilato, sebbene la distinzione possa essere sfocata a causa della presenza del compilatore bytecode. Ciò significa che i file di origine possono essere eseguiti direttamente senza creare esplicitamente un eseguibile che viene quindi eseguito.


10
Interessante, grazie. Quindi Python è considerato un linguaggio puramente interpretato?
froadie,

194
@froadie: una lingua non viene "interpretata" o "compilata" come tale. Una specifica implementazione può essere un interprete o un compilatore (o un ibrido o un compilatore JIT).
Joachim Sauer,

30
Un test di "compilato": è compilato in base alle istruzioni effettive della macchina? Il bytecode Python non è istruzioni per la macchina, né istruzioni Java "JVM", quindi nessuna di queste lingue è compilata da quella definizione. Ma entrambi "compilati" in un codice "macchina astratta" intermedio, ed entrambi sono molto più veloci dell'esecuzione del programma interpretando più o meno direttamente il codice sorgente (che è ciò che fa BASIC della vecchia scuola).
Greggo,

20
Per essere pedanti, "compilato" significa "tradotto". Python viene quindi compilato in un bytecode. AFAIK, solo Bash è veramente interpretato, tutti gli altri linguaggi "interpretati" popolari sono tutti compilati in un bytecode.
bfontaine,

13
In realtà, sono istruzioni macchina, non solo istruzioni macchina native per la CPU fisica dell'host. Quindi perché lo chiamiamo una VM? Come l'esperanto per il linguaggio assembly davvero. Oggi abbiamo persino un codice nativo per CPU immaginarie (ma ancora emulate) (lo sforzo di Mojang di interessare i bambini). Rexx è stato (o potrebbe essere) veramente interpretato, e BAT e CMD (e DCL) sono interpretati.
mckenzm,

994

Mi è stato dato di capire che Python è un linguaggio interpretato ...

Questo meme popolare non è corretto, o, piuttosto, costruito su un fraintendimento dei livelli linguistici (naturali): un errore simile sarebbe quello di dire "la Bibbia è un libro con copertina rigida". Lasciami spiegare quella similitudine ...

"La Bibbia" è "un libro" nel senso di essere una classe di (oggetti reali, fisici identificati come) libri; i libri identificati come "copie della Bibbia" dovrebbero avere qualcosa di fondamentale in comune (i contenuti, sebbene anche quelli possano essere in lingue diverse, con diverse traduzioni accettabili, livelli di note a piè di pagina e altre annotazioni) - tuttavia, quei libri sono perfettamente permesso di differenziarsi in una miriade di aspetti che non sono considerati fondamentali: tipo di rilegatura, colore della rilegatura, carattere (i) usato (i) nella stampa, eventuali illustrazioni, ampi margini scrivibili o meno, numeri e tipi di segnalibri incorporati , E così via e così via.

È del tutto possibile che una tipica stampa della Bibbia sia effettivamente rilegata in copertina rigida - dopotutto, è un libro che in genere deve essere letto e rilegato, aggiunto ai segnalibri in diversi punti, sfogliato cercando puntatori di capitoli e versetti , ecc., ecc. e una buona rilegatura con copertina rigida può prolungare la durata di una determinata copia con tale uso. Tuttavia, si tratta di questioni banali (pratiche) che non possono essere utilizzate per determinare se un determinato oggetto libro reale è una copia della Bibbia o no: le stampe tascabili sono perfettamente possibili!

Allo stesso modo, Python è "un linguaggio" nel senso di definire una classe di implementazioni linguistiche che devono essere tutte simili per alcuni aspetti fondamentali (sintassi, la maggior parte della semantica tranne quelle parti di quelle in cui sono esplicitamente autorizzati a differire) ma sono pienamente autorizzati differire in quasi ogni dettaglio di "implementazione", incluso il modo in cui gestiscono i file di origine che vengono forniti, se compilano i sorgenti in alcuni moduli di livello inferiore (e, in tal caso, quale modulo) e se salvano tali moduli compilati, su disco o altrove), come eseguono tali moduli e così via.

L'implementazione classica, CPython, è spesso chiamata semplicemente "Python" in breve - ma è solo una delle numerose implementazioni di qualità di produzione, affiancate da IronPython di Microsoft (che si compila in codici CLR, ovvero ".NET"), Jython (che compila i codici JVM), PyPy (che è scritto nello stesso Python e può essere compilato in una grande varietà di forme "back-end" incluso il linguaggio macchina generato "just-in-time"). Sono tutti Python (== "implementazioni del linguaggio Python") proprio come molti oggetti di libri superficialmente diversi possono essere tutti Bibbie (== "copie della Bibbia").

Se sei interessato a CPython in particolare: compila i file sorgente in un modulo di livello inferiore specifico di Python (noto come "bytecode"), lo fa automaticamente quando necessario (quando non esiste un file bytecode corrispondente a un file sorgente, oppure il file bytecode è più vecchio del sorgente o compilato da una diversa versione di Python), di solito salva i file bytecode su disco (per evitare di ricompilarli in futuro). OTOH IronPython generalmente si compila in codici CLR (salvandoli su disco o meno, a seconda) e Jython in codici JVM (salvandoli su disco o meno - utilizzerà l' .classestensione se li salva).

Questi moduli di livello inferiore vengono quindi eseguiti da "macchine virtuali" appropriate anche note come "interpreti": la VM CPython, il runtime .Net, la VM Java (aka JVM), a seconda dei casi.

Quindi, in questo senso (cosa fanno le implementazioni tipiche), Python è un "linguaggio interpretato" se e solo se C # e Java lo sono: tutti hanno una tipica strategia di implementazione per produrre prima il bytecode, quindi eseguirlo tramite un VM / interprete .

Più probabilmente l'attenzione si concentra su quanto "pesante", lento e cerimonia sia il processo di compilazione. CPython è progettato per compilare il più velocemente possibile, il più leggero possibile, con il minor numero di cerimonie possibile: il compilatore esegue pochissimi controlli e ottimizzazioni degli errori, quindi può funzionare velocemente e con piccole quantità di memoria, che a sua volta gli consente essere eseguito automaticamente e in modo trasparente ogni volta che è necessario, senza che l'utente debba nemmeno essere consapevole che c'è una compilazione in corso, il più delle volte. Java e C # in genere accettano più lavoro durante la compilazione (e quindi non eseguono la compilazione automatica) al fine di controllare gli errori in modo più approfondito ed eseguire ulteriori ottimizzazioni. È un continuum di squame grigie, non una situazione in bianco o nero,


2
Bella risposta. Solo una piccola correzione all'ultimo paragrafo: Python è progettato per compilare il più velocemente possibile (ecc.). Questa volta è davvero il linguaggio, con la sua mancanza di sistema e roba di tipo statico. Quando le persone parlano di lingue "interpretate", di solito significano lingue "dinamiche".
Elazar,

2
@Elazar, in realtà, altre implementazioni di Python, come PyPy, che non hanno fretta di compilare, riescono a fare l'analisi più approfondita richiesta dalla mancanza di tipizzazione statica e produrre compilazioni just-in-time su codice macchina (accelerando così programmi di lunga durata di molte volte).
Alex Martelli,

Dove si inserisce Cython qui? Lo considereresti un linguaggio diverso o è un'implementazione di Python? Inoltre, questo meme di "interpretato" vs compilato è forse solo una confusione terminologica perché la VM di Python viene spesso definita "interprete"? Sarebbe altrettanto valido chiamare gli interpreti di runtime JVM o .NET. Entrambi interpretano principalmente il bytecode nel codice macchina JIT (con alcune eccezioni di ottimizzazione della memorizzazione nella cache)
Davos,

181

Non esiste un linguaggio interpretato. L'utilizzo di un interprete o di un compilatore è puramente una caratteristica dell'implementazione e non ha assolutamente nulla a che fare con il linguaggio.

Ogni lingua può essere implementata da un interprete o da un compilatore. La stragrande maggioranza delle lingue ha almeno un'implementazione di ciascun tipo. (Ad esempio, ci sono interpreti per C e C ++ e ci sono compilatori per JavaScript, PHP, Perl, Python e Ruby.) Inoltre, la maggior parte delle implementazioni linguistiche moderne in realtà combina sia un interprete che un compilatore (o anche più compilatori).

Una lingua è solo un insieme di regole matematiche astratte. Un interprete è una delle diverse strategie di implementazione concrete per una lingua. Quei due vivono su livelli di astrazione completamente diversi. Se l'inglese fosse una lingua tipizzata, il termine "lingua interpretata" sarebbe un errore di tipo. L'affermazione "Python è un linguaggio interpretato" non è solo falsa (perché essere falsi implicherebbe che l'affermazione ha persino senso, anche se è sbagliata), semplicemente non ha senso , perché un linguaggio non può mai essere definito come "interpretato."

In particolare, se guardi alle implementazioni Python attualmente esistenti, queste sono le strategie di implementazione che stanno usando:

  • IronPython: compila in alberi DLR che il DLR compila quindi in bytecode CIL. Cosa succede al bytecode CIL dipende da quale CLI VES è in esecuzione, ma Microsoft .NET, GNU Portable.NET e Novell Mono alla fine lo compileranno in codice macchina nativo.
  • Jython: interpreta il codice sorgente Python fino a quando non identifica i percorsi di hot code, che quindi compila in bytecode JVML. Cosa succede al bytecode JVML dipende da quale JVM stai eseguendo. Maxine lo compila direttamente in codice nativo non ottimizzato fino a quando non identifica i percorsi di hot code, che quindi ricompila in codice nativo ottimizzato. HotSpot prima interpreterà il bytecode JVML e poi compilerà i percorsi degli hot code in un codice macchina ottimizzato.
  • PyPy: compila in bytecode PyPy, che viene quindi interpretato dalla VM PyPy fino a quando non identifica i percorsi di hot code che quindi compila in codice nativo, bytecode JVML o bytecode CIL a seconda della piattaforma su cui si esegue.
  • CPython: compila in bytecode CPython che poi interpreta.
  • Stackless Python: compila in bytecode CPython che poi interpreta.
  • Unladen Swallow: compila in bytecode CPython che poi interpreta fino a quando non identifica i percorsi di hot code che poi compila in LLVM IR che il compilatore LLVM compila quindi in codice macchina nativo.
  • Cython: compila il codice Python in codice C portatile, che viene quindi compilato con un compilatore C standard
  • Nuitka: compila il codice Python in codice C ++ dipendente dalla macchina, che viene quindi compilato con un compilatore C standard

Potresti notare che ognuna delle implementazioni in quella lista (più alcune altre che non ho menzionato, come tinypy, Shedskin o Psyco) ha un compilatore. In effetti, per quanto ne so, al momento non esiste un'implementazione di Python che sia puramente interpretata, non esiste una tale implementazione pianificata e non c'è mai stata una tale implementazione.

Non solo il termine "linguaggio interpretato" non ha senso, anche se lo interpretate come "linguaggio con implementazione interpretata", non è chiaramente vero. Chiunque te lo abbia detto, ovviamente non sa di cosa sta parlando.

In particolare, i .pycfile visualizzati sono file di bytecode memorizzati nella cache prodotti da CPython, Stackless Python o Unladen Swallow.


5
Base di vecchia scuola come MSBASIC non aveva forma intermedia. Il programma è stato interpretato direttamente dalla forma di origine (o vicino alla fonte, una forma in cui le parole chiave erano rappresentate da token a 1 byte e la riga # da numeri binari a 2 byte, ma il resto era solo ASCII). Quindi in effetti un 'goto' richiederebbe diverse quantità di tempo a seconda di quante linee sorgente ha dovuto cercare cercando la destinazione corrispondente. Espressioni come * b-2 * cos (x) sono state effettivamente riesaminate ogni volta che sono state eseguite.
Greggo,

4
@greggo: E se vuoi andare ancora più alla vecchia scuola, la versione originale di BASIC era un compilatore di codice nativo. Ciò dovrebbe dimostrare quanto sia ridicola l'idea di un linguaggio "compilato" o "interpretato".
Jörg W Mittag,

Grazie per aver spiegato come si comportano i vari compilatori / interpreti Python. Mi chiedo se ci sono ancora buoni compilatori Python che generano C o JavaScript efficienti. Sembra molto fattibile, forse non per il consumo di massa, ma almeno per un ragionevole sottoinsieme di Python. Inoltre mi chiedo cosa sia Cython.
personal_cloud

Cython è stato menzionato in SciPy 2009, ma posso perdonarti per non averlo saputo nel 2010 (eccomi qui nel 2017 solo ora che lo sto imparando). Dovremmo comunque trovare un esempio JavaScript ... Jython non ha senso per me (Java non era già morto entro il 2009? Beh, hmm, forse no ... Il boost di C ++ non era poi così buono)
personal_cloud

1
@personal_cloud: non seguo del tutto il tuo commento. Sì, certo, lo so di Cython, ma cosa c'entra questo con qualcosa? Non è un'implementazione di Python, è un linguaggio completamente diverso. Inoltre, non è davvero difficile trovare un esempio JavaScript, infatti, tutte le implementazioni JavaScript tradizionali attualmente esistenti hanno compilatori. Infine, Jython è un'implementazione di Python proprio come qualsiasi altra implementazione di Python. Ed è un'implementazione di un linguaggio sulla piattaforma Java proprio come qualsiasi altra implementazione di linguaggio sulla piattaforma Java.
Jörg W Mittag,

61

Questi vengono creati dall'interprete Python quando un .pyfile viene importato e contengono il "bytecode compilato" del modulo / programma importato, con l'idea che la "traduzione" dal codice sorgente al bytecode (che deve essere eseguita una sola volta) può essere saltato sui messaggi successivi importse .pycè più recente del .pyfile corrispondente , accelerando così un po 'l'avvio. Ma è ancora interpretato.


10
Vero. Tranne il fatto che molte librerie Python di base sono scritte in C. Quindi parti di Python Run interpretate, in parte Run in C. Puoi fare lo stesso con i tuoi bit di codice sensibili alle prestazioni.
bwawok,

44

Per accelerare il caricamento dei moduli, Python memorizza nella cache il contenuto compilato dei moduli in .pyc.

CPython compila il suo codice sorgente in "codice byte" e, per motivi di prestazioni, memorizza nella cache questo codice byte sul file system ogni volta che il file sorgente viene modificato. Questo rende il caricamento dei moduli Python molto più veloce perché la fase di compilazione può essere bypassata. Quando il file sorgente è foo.py, CPython memorizza nella cache il codice byte in un file foo.pyc proprio accanto alla fonte.

In python3, le macchine di importazione di Python sono estese per scrivere e cercare file cache di codice byte in una singola directory all'interno di ogni directory del pacchetto Python. Questa directory si chiamerà __pycache__.

Ecco un diagramma di flusso che descrive come vengono caricati i moduli:

inserisci qui la descrizione dell'immagine

Per maggiori informazioni:

ref: PEP3147
ref: file Python “compilati”


38

Questo è per i principianti,

Python compila automaticamente lo script in codice compilato, il cosiddetto codice byte, prima di eseguirlo.

L'esecuzione di uno script non è considerata un'importazione e non verrà creato .pyc.

Ad esempio, se si dispone di un file di script abc.py che importa un altro modulo xyz.py , quando si esegue abc.py , verrà creato xyz.pyc dall'importazione di xyz, ma nessun file abc.pyc verrà creato da abc. py non viene importato.

Se è necessario creare un file .pyc per un modulo non importato, è possibile utilizzare i moduli py_compilee compileall.

Il py_compilemodulo può compilare manualmente qualsiasi modulo. Un modo è utilizzare la py_compile.compilefunzione in quel modulo in modo interattivo:

>>> import py_compile
>>> py_compile.compile('abc.py')

Questo scriverà il .pyc nella stessa posizione di abc.py (puoi sovrascriverlo con il parametro opzionale cfile).

Puoi anche compilare automaticamente tutti i file in una directory o directory usando il modulo compileall.

python -m compileall

Se il nome della directory (la directory corrente in questo esempio) viene omesso, il modulo compila tutto ciò che si trova su sys.path


6
e qual è il vantaggio della compilazione per ottenere abc.py?
Saher Ahwal,

@SaherAhwal Un vantaggio che mi viene in mente è il controllo della sintassi.
Yi Bao,

20

Python (almeno l'implementazione più comune di esso) segue uno schema di compilazione del codice sorgente originale in codici byte, quindi di interpretazione dei codici byte su una macchina virtuale. Questo significa (di nuovo, l'implementazione più comune) non è né un interprete puro né un compilatore puro.

L'altro lato di questo è, tuttavia, che il processo di compilazione è per lo più nascosto: i file .pyc sono sostanzialmente trattati come una cache; accelerano le cose, ma normalmente non devi esserne affatto consapevole. Invalida automaticamente e li carica nuovamente (ricompila nuovamente il codice sorgente) quando necessario in base ai timestamp di data / ora del file.

Circa l'unica volta che ho visto un problema con questo è stato quando un file bytecode compilato in qualche modo ha avuto un timestamp nel futuro, il che significava che sembrava sempre più nuovo del file di origine. Dal momento che sembrava più recente, il file di origine non è mai stato ricompilato, quindi indipendentemente dalle modifiche apportate, sono state ignorate ...


12

Il file * .py di Python è solo un file di testo in cui scrivi alcune righe di codice. Quando si tenta di eseguire questo file usando dire "python nomefile.py"

Questo comando richiama Python Virtual Machine. Python Virtual Machine ha 2 componenti: "compilatore" e "interprete". L'interprete non può leggere direttamente il testo nel file * .py, quindi questo testo viene prima convertito in un codice byte che è indirizzato al PVM (non hardware ma PVM) . PVM esegue questo codice byte. Viene anche generato il file * .pyc, come parte dell'esecuzione che esegue l'operazione di importazione su file nella shell o in qualche altro file.

Se questo file * .pyc è già generato, ogni volta che esegui / esegui il tuo file * .py, il sistema carica direttamente il tuo file * .pyc che non necessita di alcuna compilazione (questo ti farà risparmiare alcuni cicli macchina del processore).

Una volta generato il file * .pyc, non è necessario il file * .py, a meno che non venga modificato.


7

Il codice Python passa attraverso 2 fasi. Il primo passo compila il codice in file .pyc che in realtà è un bytecode. Quindi questo file .pyc (bytecode) viene interpretato usando l'interprete CPython. Si prega di fare riferimento a questo link. Qui il processo di compilazione ed esecuzione del codice è spiegato in termini semplici.

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.