Si se interpreta Python, ¿qué son los archivos .pyc?

1084

Se me ha dado a entender que Python es un lenguaje interpretado ...
Sin embargo, cuando miro mi código fuente de Python veo .pycarchivos, que Windows identifica como "Archivos compilados de Python".

¿Dónde entran estos?

froadie
fuente
3
Consulte stackoverflow.com/questions/11433579/… para obtener una justificación. En una palabra: velocidad.
user7610
Consulte también "Todos los programas se interpretan". ¿Cómo?
Chankey Pathak
¿Significa que incluso Python tiene ese 'Escribir una vez, ejecutar en cualquier lugar' como Java?
Mrak Vladar
2
@MrakVladar Incluso Java es "Escribir una vez, ejecutar en cualquier lugar [que tenga una JVM]". Python no es diferente; es "ejecutar en cualquier lugar donde tenga una máquina virtual Python". La gran diferencia es que la mayoría de las implementaciones de Python combinan el compilador y el intérprete en un solo ejecutable, en lugar de separarlos como javay javac.
chepner el

Respuestas:

661

Contienen código de bytes , que es a lo que el intérprete de Python compila la fuente. Este código es ejecutado por la máquina virtual de Python.

La documentación de Python explica la definición de esta manera:

Python es un lenguaje interpretado, a diferencia de uno compilado, aunque la distinción puede ser borrosa debido a la presencia del compilador de bytecode. Esto significa que los archivos fuente pueden ejecutarse directamente sin crear explícitamente un ejecutable que luego se ejecuta.

relajarse
fuente
10
Interesante, gracias. Entonces, ¿se considera Python un lenguaje puramente interpretado?
froadie
194
@froadie: un lenguaje no se "interpreta" o "compila" como tal. Una implementación específica puede ser un intérprete o un compilador (o un compilador híbrido o JIT).
Joachim Sauer
30
Una prueba de 'compilado': ¿está compilado según las instrucciones reales de la máquina? Python bytecode no son instrucciones de máquina, y tampoco lo son las instrucciones Java 'JVM', por lo que ninguno de estos lenguajes está compilado por esa definición. Pero ambos se 'compilaron' en un código intermedio de 'máquina abstracta', y ambos son mucho más rápidos que ejecutar el programa interpretando más o menos directamente el código fuente (que es lo que hace BASIC de la vieja escuela).
greggo
20
Para ser pedante, 'compilado' significa 'traducido'. Python luego se compila en un bytecode. AFAIK, solo Bash se interpreta realmente , todos los demás lenguajes "interpretados" populares se compilan en un código de bytes.
bfontaine
13
En realidad, son instrucciones de máquina, solo que no son instrucciones de máquina nativas para la CPU física del host. ¿Por eso lo llamamos VM? Como esperanto para el lenguaje ensamblador realmente. Hoy en día incluso tenemos código nativo para CPU ficticias (pero aún emuladas) (el esfuerzo de Mojang para interesar a los niños). Rexx fue (o podría ser) verdaderamente interpretado, y BAT y CMD (y DCL) son interpretados.
mckenzm
995

Me han dado a entender que Python es un lenguaje interpretado ...

Este meme popular es incorrecto o, más bien, se basa en un malentendido de los niveles del lenguaje (natural): un error similar sería decir "la Biblia es un libro de tapa dura". Déjame explicarte ese símil ...

"La Biblia" es "un libro" en el sentido de ser una clase de (objetos físicos reales identificados como) libros; Se supone que los libros identificados como "copias de la Biblia" tienen algo fundamental en común (los contenidos, aunque incluso pueden estar en diferentes idiomas, con diferentes traducciones aceptables, niveles de notas al pie y otras anotaciones), sin embargo, esos libros son perfectamente permitido diferir en una miríada de aspectos que no se consideran fundamentales: tipo de encuadernación, color de encuadernación, fuente (s) utilizada (s) en la impresión, ilustraciones si las hay, amplios márgenes de escritura o no, números y tipos de marcadores incorporados , y así sucesivamente y así sucesivamente.

Es muy posible que una impresión típica de la Biblia esté en una encuadernación de tapa dura; después de todo, es un libro que normalmente debe leerse una y otra vez, marcado en varios lugares, hojeado buscando punteros de capítulo y versículo. , etc., etc., y una buena encuadernación de tapa dura puede hacer que una copia determinada dure más tiempo bajo tal uso. Sin embargo, estos son problemas mundanos (prácticos) que no se pueden usar para determinar si un objeto de libro real es una copia de la Biblia o no: ¡las impresiones en rústica son perfectamente posibles!

De manera similar, Python es "un lenguaje" en el sentido de definir una clase de implementaciones de lenguaje que deben ser todas similares en algunos aspectos fundamentales (sintaxis, la mayoría de las semánticas, excepto aquellas partes de aquellas en las que se les permite explícitamente diferir) pero están totalmente permitidas. para diferir en casi todos los detalles de "implementación", incluida la forma en que manejan los archivos fuente que se les da, si compilan las fuentes en algunos formularios de nivel inferior (y, de ser así, qué formulario) y si guardan dichos archivos formularios compilados, en disco o en otro lugar), cómo ejecutan dichos formularios, etc.

La implementación clásica, CPython, a menudo se llama simplemente "Python" para abreviar, pero es solo una de varias implementaciones de calidad de producción, junto con IronPython de Microsoft (que compila los códigos CLR, es decir, ".NET"), Jython (que se compila en códigos JVM), PyPy (que está escrito en Python y puede compilarse en una gran variedad de formas "back-end", incluido el lenguaje de máquina generado "justo a tiempo"). Todos son Python (== "implementaciones del lenguaje Python") al igual que muchos objetos de libro superficialmente diferentes pueden ser Biblias (== "copias de La Biblia").

Si está interesado en CPython específicamente: compila los archivos fuente en un formulario de nivel inferior específico de Python (conocido como "código de bytes"), lo hace automáticamente cuando es necesario (cuando no hay un archivo de código de bytes correspondiente a un archivo fuente, o el archivo de código de bytes es más antiguo que el de origen o está compilado por una versión diferente de Python), generalmente guarda los archivos de código de bytes en el disco (para evitar volver a compilarlos en el futuro). OTOH IronPython normalmente compilará en códigos CLR (guardándolos en el disco o no, dependiendo) y Jython en códigos JVM (guardándolos en el disco o no; usará la .classextensión si los guarda).

Estos formularios de nivel inferior son ejecutados por "máquinas virtuales" apropiadas también conocidas como "intérpretes": la VM CPython, el tiempo de ejecución .Net, la VM Java (también conocida como JVM), según corresponda.

Entonces, en este sentido (qué hacen las implementaciones típicas), Python es un "lenguaje interpretado" si y solo si C # y Java lo son: todos ellos tienen una estrategia de implementación típica de producir primero el código de bytes, luego ejecutarlo a través de un VM / intérprete .

Lo más probable es que el enfoque se centre en cuán "pesado", lento y alto es el proceso de compilación. CPython está diseñado para compilar lo más rápido posible, lo más liviano posible, con la menor ceremonia posible: el compilador realiza muy poca verificación y optimización de errores, por lo que puede ejecutarse rápidamente y en pequeñas cantidades de memoria, lo que a su vez lo permite se ejecute de forma automática y transparente cuando sea necesario, sin que el usuario tenga que darse cuenta de que hay una compilación, la mayoría de las veces. Java y C # generalmente aceptan más trabajo durante la compilación (y, por lo tanto, no realizan la compilación automática) para verificar los errores más a fondo y realizar más optimizaciones. Es un continuo de escamas grises, no una situación en blanco o negro,

Alex Martelli
fuente
2
Hermosa respuesta Solo una pequeña corrección al último párrafo: Python está diseñado para compilar lo más rápido posible (etc.). Esta vez realmente es el lenguaje, con su falta de sistema de tipo estático y demás. Cuando las personas hablan de idiomas "interpretados", generalmente se refieren a idiomas "dinámicos".
Elazar
2
@Elazar, en realidad, otras implementaciones de Python, como PyPy, que no tienen prisa en compilar, logran hacer el análisis más exhaustivo requerido por la falta de tipeo estático y producen una compilación justo a tiempo para el código de máquina (acelerando así programas de larga duración por muchas veces).
Alex Martelli
¿Dónde encaja Cython aquí? ¿Lo considerarías un lenguaje diferente o es una implementación de Python? Además, ¿este meme de "interpretado" vs compilado es quizás solo una confusión de terminología porque la VM de Python a menudo se conoce como su "intérprete"? Sería igual de válido llamar a los intérpretes de tiempo de ejecución JVM o .NET. Ambos interpretan principalmente el código de bytes en el código de máquina JIT (con algunas excepciones de optimización de almacenamiento en caché)
Davos
181

No existe un lenguaje interpretado. Si se utiliza un intérprete o un compilador es puramente un rasgo de la implementación y no tiene absolutamente nada que ver con el lenguaje.

Cada idioma puede ser implementado por un intérprete o un compilador. La gran mayoría de los idiomas tienen al menos una implementación de cada tipo. (Por ejemplo, hay intérpretes para C y C ++ y hay compiladores para JavaScript, PHP, Perl, Python y Ruby). Además, la mayoría de las implementaciones de lenguaje moderno en realidad combinan un intérprete y un compilador (o incluso varios compiladores).

Un lenguaje es solo un conjunto de reglas matemáticas abstractas. Un intérprete es una de varias estrategias de implementación concretas para un lenguaje. Esos dos viven en niveles de abstracción completamente diferentes. Si el inglés fuera un idioma escrito, el término "idioma interpretado" sería un error de tipo. La afirmación "Python es un lenguaje interpretado" no es solo falsa (porque ser falso implicaría que la afirmación incluso tiene sentido, incluso si es incorrecta), simplemente no tiene sentido , porque un lenguaje nunca puede definirse como "interpretado."

En particular, si observa las implementaciones actuales de Python, estas son las estrategias de implementación que están utilizando:

  • IronPython: compila en árboles DLR que DLR luego compila en código de bytes CIL. Lo que sucede con el código de bytes CIL depende de qué CLI VES esté ejecutando, pero Microsoft .NET, GNU Portable.NET y Novell Mono eventualmente lo compilarán en código máquina nativo.
  • Jython: interpreta el código fuente de Python hasta que identifica las rutas de código activo, que luego compila en el código de bytes JVML. Lo que sucede con el código de bytes JVML depende de qué JVM esté ejecutando. Maxine lo compilará directamente en código nativo no optimizado hasta que identifique las rutas de código activo, que luego se vuelve a compilar en código nativo optimizado. HotSpot primero interpretará el código de bytes JVML y luego finalmente compilará las rutas de los códigos activos para obtener un código de máquina optimizado.
  • PyPy: compila a PyPy bytecode, que luego es interpretado por PyPy VM hasta que identifica las rutas de hot code que luego compila en código nativo, JVML bytecode o CIL bytecode dependiendo de la plataforma en la que se esté ejecutando.
  • CPython: compila a CPython bytecode que luego interpreta.
  • Python apilable: compila en el bytecode de CPython que luego interpreta.
  • Swallow sin carga: compila en el bytecode de CPython que luego interpreta hasta que identifica las rutas de hot code que luego compila en LLVM IR que el compilador LLVM luego compila en el código de máquina nativo.
  • Cython: compila código Python en código C portátil, que luego se compila con un compilador C estándar
  • Nuitka: compila código Python en código C ++ dependiente de la máquina, que luego se compila con un compilador C estándar

Puede notar que cada una de las implementaciones en esa lista (además de algunas otras que no mencioné, como tinypy, Shedskin o Psyco) tiene un compilador. De hecho, hasta donde yo sé, actualmente no existe una implementación de Python que sea puramente interpretada, no hay tal implementación planificada y nunca ha habido tal implementación.

El término "lenguaje interpretado" no solo no tiene sentido, incluso si lo interpreta como "lenguaje con implementación interpretada", claramente no es cierto. Quien te haya dicho eso, obviamente no sabe de qué está hablando.

En particular, los .pycarchivos que está viendo son archivos de código de bytes en caché producidos por CPython, Stackless Python o Unladen Swallow.

Jörg W Mittag
fuente
66
La vieja escuela básica como MSBASIC no tenía forma intermedia. El programa se interpretó directamente desde el formulario fuente (o fuente cercana, un formulario en el que las palabras clave estaban representadas por tokens de 1 byte y los números de línea por entradas binarias de 2 byte, pero el resto era solo ASCII). Entonces, de hecho, un 'goto' tomaría diferentes cantidades de tiempo dependiendo de cuántas líneas de origen tuviera que buscar buscando el destino correspondiente. Expresiones como a * b-2 * cos (x) se volvieron a analizar de manera efectiva cada vez que se ejecutaron.
greggo
44
@greggo: Y si quieres ir aún más a la vieja escuela, la versión original de BASIC era un compilador de código nativo. Esto debería demostrar cuán ridícula es la noción de un lenguaje "compilado" o "interpretado".
Jörg W Mittag
Gracias por explicar cómo se comportan los diversos compiladores / intérpretes de Python. Me pregunto si todavía hay buenos compiladores de Python que generen C o JavaScript eficientes. Parece muy factible, tal vez no para consumo masivo, sino para un subconjunto razonable de Python al menos. También me pregunto qué es Cython.
personal_cloud
Cython se mencionó en SciPy 2009, pero puedo perdonarlo por no haberlo sabido en 2010 (aquí estoy en 2017, justo ahora que lo estoy aprendiendo). Todavía tenemos que encontrar un ejemplo de JavaScript ... Jython no tiene sentido para mí (ya no estaba muerta de Java para el año 2009 Bien hmm, tal vez no ... C ++ impulso no era tan bueno en ese entonces?)
personal_cloud
1
@personal_cloud: no sigo tu comentario. Sí, por supuesto, sé sobre Cython, pero ¿qué tiene eso que ver con algo? No es una implementación de Python, es un lenguaje completamente diferente. Además, en realidad no es difícil encontrar un ejemplo de JavaScript, de hecho, todas las implementaciones de JavaScript convencionales actualmente existentes tienen compiladores. Por último, Jython es una implementación de Python como cualquier otra implementación de Python. Y es una implementación de un lenguaje en la plataforma Java como cualquier otra implementación de lenguaje en la plataforma Java.
Jörg W Mittag
61

Estos son creados por el intérprete de Python cuando .pyse importa un archivo, y contienen el "código de bytes compilado" del módulo / programa importado, la idea es que la "traducción" del código fuente al código de bytes (que solo debe hacerse una vez) se puede omitir en los correos subsiguientes importsi el archivo .pyces más reciente que el correspondiente .py, lo que acelera un poco el inicio Pero aún se interpreta.

Tim Pietzcker
fuente
10
Cierto. Excepto que muchas bibliotecas centrales de Python están escritas en C. Entonces, las partes de Python se interpretan, la parte se ejecuta en C. Puede hacer lo mismo con sus propios bits de código sensibles al rendimiento.
bwawok
44

Para acelerar la carga de módulos, Python almacena en caché el contenido compilado de los módulos en .pyc.

CPython compila su código fuente en "código de byte" y, por razones de rendimiento, almacena en caché este código de byte en el sistema de archivos cuando el archivo fuente tiene cambios. Esto hace que la carga de los módulos de Python sea mucho más rápida porque se puede omitir la fase de compilación. Cuando su archivo fuente es foo.py, CPython almacena en caché el código de bytes en un archivo foo.pyc justo al lado de la fuente.

En python3, la maquinaria de importación de Python se extiende para escribir y buscar archivos de caché de código de bytes en un solo directorio dentro de cada directorio de paquetes de Python. Este directorio se llamará __pycache__.

Aquí hay un diagrama de flujo que describe cómo se cargan los módulos:

ingrese la descripción de la imagen aquí

Para más información:

ref: PEP3147
ref: archivos Python "compilados"

hxysayhi
fuente
38

ESTO ES PARA PRINCIPIANTES,

Python compila automáticamente su script en código compilado, llamado código de bytes, antes de ejecutarlo.

Ejecutar un script no se considera una importación y no se creará .pyc.

Por ejemplo, si tiene un archivo de script abc.py que las importaciones de otro módulo xyz.py , al ejecutar abc.py , xyz.pyc será creado ya ha sido importada XYZ, pero ningún archivo abc.pyc será creado desde ABC. Py no se está importando.

Si necesita crear un archivo .pyc para un módulo que no se importa, puede usar los módulos py_compiley compileall.

El py_compilemódulo puede compilar manualmente cualquier módulo. Una forma es usar la py_compile.compilefunción en ese módulo de forma interactiva:

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

Esto escribirá el .pyc en la misma ubicación que abc.py (puede anularlo con el parámetro opcional cfile).

También puede compilar automáticamente todos los archivos en un directorio o directorios utilizando el módulo compileall.

python -m compileall

Si se omite el nombre del directorio (el directorio actual en este ejemplo), el módulo compila todo lo que se encuentra en sys.path

MAX
fuente
66
¿Y cuál es el beneficio de compilar para obtener abc.py?
Saher Ahwal
@SaherAhwal Un beneficio en el que puedo pensar es en la verificación de sintaxis.
Yi Bao
20

Python (al menos la implementación más común de este) sigue un patrón de compilación de la fuente original en códigos de bytes, luego interpreta los códigos de bytes en una máquina virtual. Esto significa (nuevamente, la implementación más común) no es un intérprete puro ni un compilador puro.

Sin embargo, el otro lado de esto es que el proceso de compilación está mayormente oculto: los archivos .pyc se tratan básicamente como un caché; aceleran las cosas, pero normalmente no tienes que estar al tanto de ellas. Invalida y vuelve a cargarlos automáticamente (vuelve a compilar el código fuente) cuando es necesario en función de las marcas de fecha / hora del archivo.

Casi la única vez que vi un problema con esto fue cuando un archivo de código de bytes compilado de alguna manera tenía una marca de tiempo en el futuro, lo que significaba que siempre parecía más nuevo que el archivo de origen. Como parecía más nuevo, el archivo fuente nunca se volvió a compilar, por lo que no importa qué cambios haya realizado, se ignoraron ...

Jerry Coffin
fuente
12

El archivo * .py de Python es solo un archivo de texto en el que escribe algunas líneas de código. Cuando intentes ejecutar este archivo usando "python filename.py"

Este comando invoca la máquina virtual Python. Python Virtual Machine tiene 2 componentes: "compilador" e "intérprete". El intérprete no puede leer directamente el texto en el archivo * .py, por lo que este texto se convierte primero en un código de bytes dirigido al PVM (no al hardware sino al PVM) . PVM ejecuta este código de byte. El archivo * .pyc también se genera, como parte de su ejecución, que realiza su operación de importación en el archivo de shell o en algún otro archivo.

Si este archivo * .pyc ya está generado, cada vez que ejecute / ejecute su archivo * .py, el sistema cargará directamente su archivo * .pyc que no necesitará ninguna compilación (esto le ahorrará algunos ciclos de procesador de la máquina).

Una vez que se genera el archivo * .pyc, no es necesario el archivo * .py, a menos que lo edite.

Vishal Mopari
fuente
7

El código de Python pasa por 2 etapas. El primer paso compila el código en archivos .pyc, que en realidad es un bytecode. Entonces este archivo .pyc (bytecode) se interpreta utilizando el intérprete CPython. Por favor, consulte este enlace. Aquí el proceso de compilación y ejecución de código se explica en términos fáciles.

Tango
fuente