¿Cuándo se actualizan los archivos .pyc?

91

Entiendo que los archivos ".pyc" son versiones compiladas de los archivos ".py" de texto plano, creados en tiempo de ejecución para que los programas se ejecuten más rápido. Sin embargo, he observado algunas cosas:

  1. Tras la modificación de archivos "py", el comportamiento del programa cambia. Esto indica que los archivos "py" están compilados o al menos pasan por algún tipo de proceso de hash o comparan marcas de tiempo para saber si deben volver a compilarse o no.
  2. Al eliminar todos los archivos ".pyc" ( rm *.pyc), algunas veces el comportamiento del programa cambiará. Lo que indicaría que no se están compilando en la actualización de ".py" s.

Preguntas:

  • ¿Cómo deciden cuándo se compilan?
  • ¿Hay alguna forma de garantizar que tengan un control más estricto durante el desarrollo?
Aaron Schif
fuente
14
Tenga cuidado con la eliminación de archivos .pyc con rm *.pyc. Esto no eliminará los archivos .pyc en carpetas anidadas. Úselo en su find . -name '*.pyc' -deletelugar
Zags
6
Quizás una nota sobre su pregunta: un programa no se ejecuta más rápido cuando se lee desde un archivo '.pyc' o '.pyo' que cuando se lee desde un archivo '.py'; lo único que es más rápido en los archivos '.pyc' o '.pyo' es la velocidad con la que se cargan. enlace
maggie
@maggie ¿cuál es la diferencia entre el tiempo de carga y el de ejecución?
Daniel Springer
3
@Dani loading es el tiempo que lleva leer y luego compilar el programa. El tiempo de ejecución es cuando el programa se está ejecutando realmente, lo que ocurre después de la carga. Si quiere ser técnico, los tipos de tiempo son tiempo de carga, tiempo de compilación, tiempo de enlace y tiempo de ejecución. Hacer un .pyc elimina la parte del tiempo de compilación.
Eric Klien
@EricKlien agradece al hombre
Daniel Springer

Respuestas:

79

Los .pycarchivos se crean (y posiblemente se sobrescriben) solo cuando ese archivo de Python es importado por algún otro script. Si se llama a la importación, Python comprueba si la .pycmarca de tiempo interna del archivo no es anterior al .pyarchivo correspondiente . Si es así, carga el .pyc; si no lo es o si .pycaún no existe, Python compila el .pyarchivo en a .pycy lo carga.

¿Qué quiere decir con "control más estricto"?

DaveTheScientist
fuente
3
Puedo solucionar problemas con rm *.pyc. Sé que si fuerzo la recreación de todos los archivos, se solucionan algunos problemas, lo que indica que los archivos no se vuelven a compilar por sí mismos. Supongo que si usan las marcas de tiempo, no hay forma de hacer que este comportamiento sea más estricto, pero el problema persiste.
Aaron Schif
13
Esto no es muy correcto. No es necesario que las marcas de tiempo coincidan (y normalmente no lo hacen). La .pycmarca de tiempo 'debe ser más antigua que la .pymarca de tiempo correspondiente para activar una recompilación.
Tim Pietzcker
4
@ Aaron, ¿Es posible que esté cambiando los archivos .py y, en el proceso, haciéndolos más antiguos (por ejemplo, copiándolos desde otro directorio, utilizando una operación que conserva el 'tiempo de modificación')?
greggo
1
@greggo, estoy usando git y actualizando desde un repositorio, así que sí en cierto modo. Eso podría hacerlo. Gracias.
Aaron Schif
1
Bueno saber. ¿Qué tal corregir tu respuesta entonces?
Piotr Dobrogost
29

Archivos .pyc generados cada vez que se importan los elementos de código correspondientes y se actualizan si los archivos de código correspondientes se han actualizado. Si se eliminan los archivos .pyc, se volverán a generar automáticamente. Sin embargo, no se eliminan automáticamente cuando se eliminan los archivos de código correspondientes.

Esto puede causar algunos errores realmente divertidos durante la refactorización a nivel de archivo.

En primer lugar, puede terminar enviando un código que solo funciona en su máquina y en la de nadie más. Si tiene referencias colgantes a archivos que eliminó, estos seguirán funcionando localmente si no elimina manualmente los archivos .pyc relevantes porque los archivos .pyc se pueden usar en las importaciones. Esto se agrava con el hecho de que un sistema de control de versiones configurado correctamente solo enviará archivos .py al repositorio central, no archivos .pyc, lo que significa que su código puede pasar la "prueba de importación" (todo se importa bien) sin problemas y no trabajar en la computadora de otra persona.

En segundo lugar, puede tener algunos errores bastante terribles si convierte los paquetes en módulos. Cuando convierte un paquete (una carpeta con un __init__.pyarchivo) en un módulo (un archivo .py), los archivos .pyc que alguna vez representaron ese paquete permanecen. En particular, los __init__.pycrestos. Entonces, si tiene el paquete foo con algún código que no importa, luego elimine ese paquete y cree un archivo foo.py con alguna función def bar(): passy ejecute:

from foo import bar

usted obtiene:

ImportError: cannot import name bar

porque python todavía está usando los archivos .pyc antiguos del paquete foo, ninguno de los cuales define bar. Esto puede ser especialmente problemático en un servidor web, donde el código totalmente funcional puede romperse debido a archivos .pyc.

Como resultado de estos dos motivos (y posiblemente otros), su código de implementación y el código de prueba deben eliminar los archivos .pyc, como con la siguiente línea de bash:

find . -name '*.pyc' -delete

Además, a partir de Python 2.6, puede ejecutar Python con la -Bbandera para no usar archivos .pyc. Consulte ¿Cómo evitar los archivos .pyc? para más detalles.

Consulte también: ¿Cómo elimino todos los archivos .pyc de un proyecto?

Zags
fuente
"Cuando convierte un módulo (una carpeta con un __init__.pyarchivo) ...". Eso sería un paquete, no un módulo.
Robert David Grant
2
En particular, los __init__.pycrestos. - ¿Cómo? Como un paquete es un directorio, eliminar un paquete significa eliminar el directorio, por lo que no quedan archivos…
Piotr Dobrogost
3
@PiotrDobrogost El control de fuente administrado adecuadamente implica no verificar sus archivos pyc en la fuente. Entonces, si bien puede eliminar la carpeta, incluidos los archivos pyc, en su copia local, no se eliminará para otra persona que haga un git pull. Esto puede bloquear su servidor si su implementación también involucra un git pull.
Zags
Hay muchas razones para no confiar en que su entorno de desarrollo sea representativo de dónde se implementará su código. Este .pycproblema también es una razón: dependencias ocultas en el sistema operativo y los niveles de parches de utilidad, .soarchivos , archivos de configuración, otras bibliotecas de Python (si no está ejecutando en un entorno virtual), vars de entorno oscuras ... la lista continúa. Para ser minucioso y encontrar todos estos problemas, debe hacer una copia limpia de su código en un repositorio de git o publicar como un paquete en un servidor de estilo PyPi, y hacer una clonación completa o una configuración en una máquina virtual nueva. Algunos de esos problemas potenciales hacen que este .pycproblema palidezca en comparación.
Chris Johnson