2010-02-14 23 views
17

Hace un tiempo tuve que actualizar algunos servidores de Python 2.4 a Python 2.5. Descubrí que los archivos .pyc creados en Python 2.4 colapsarían cuando Python 2.5 intentara ejecutarlos.¿Los archivos Python 2.5 .pyc son compatibles con los archivos .pyc de Python 2.6?

¿Esto sucederá nuevamente cuando actualice de 2.5 a 2.6?

EDIT: Aquí hay un poco más de detalle

Tengo un servidor de archivos que contiene el código Python. A esto se accede tanto por los servidores Ubuntu como Windows para ejecutar el código python. Cuando ejecutan el código producen archivos .pyc en el servidor de archivos.

Descubrí que cuando actualicé una de las máquinas servidor de Python 2.4 a 2.5 tuve problemas con los archivos .pyc. Ahora no estoy seguro de si era una máquina que ejecutaba 2.5 que intentaba ejecutar 2.4 bytecode o si era una máquina 2.4 que intentaba ejecutar 2.5 bytecode, pero si borraba el bytecode todo iba bien hasta el próximo bytecode clash.

Actualicé todas las máquinas a 2.5 y el problema desapareció.

Respuesta

13

En general, .pyc los archivos son específicos de una versión de Python (aunque son portátiles en diferentes arquitecturas de máquina, siempre que ejecuten la misma versión); los archivos llevan la información sobre la versión de Python relevante en sus encabezados, por lo que si deja los archivos correspondientes .py junto a los .pyc, se reconstruirá el .pyc cada vez que se use una versión de Python diferente para importar esos módulos."Intentar ejecutar" archivos de la versión incorrecta .pyc es algo de lo que nunca había oído hablar. ¿Qué arquitecturas estuvieron involucradas? ¿Los archivos .py estaban como deberían?

Editar: como el OP aclaró que los choques se produjo cuando estaba corriendo tanto Python 2.4 y Python 2.5 programas en el mismo .py archivos (desde dos servidores diferentes, que comparten una unidad de red), la explicación de la los accidentes se vuelven fáciles. Los archivos .py fueron recompilados todo el tiempo - por el 2.4 Python cuando el 2.5 había sido el que los ejecutaba más recientemente, y viceversa - y por lo tanto los archivos .pyc estaban frenéticamente ocupados y se reescribían todo el tiempo. El bloqueo adecuado de archivos en unidades de red (especialmente, pero no exclusivamente, en diferentes sistemas operativos) es notoriamente difícil de lograr. Entonces debe haber sucedido lo siguiente (los roles podrían cambiarse): el servidor 2.4 acababa de determinar que un archivo .pyc estaba bien para él y comenzó a leerlo; antes de que pudiera terminar de leer, el servidor 2.5 (habiendo determinado previamente que el módulo necesitaba ser recompilado) escribió sobre él; por lo que el servidor 2.4 terminó con un búfer de memoria que tenía (digamos) los primeros 4K bytes de la versión 2.4 y los siguientes 4K bytes de la versión 2.5. Cuando entonces usó ese búfer destrozado, como era de esperar ... crash !!!

Esto puede ser un problema real si alguna vez continuamente intenta ejecutar un solo conjunto de archivos .py de dos o más versiones diferentes de Python (incluso en el mismo servidor, sin las complicaciones adicionales de las unidades de red). La solución "adecuada" sería algo así como virtualenv. El truco (simple, pero sucio) que adoptamos en el trabajo (hace muchos años, pero todavía está en producción ...!) Es parchear cada versión de Python para producir y usar una extensión diferente para sus archivos de códigos de bytes compilados: .pyc (o .pyo) para Python 1.5.2 (que era la versión más estable del "sistema" cuando comenzamos a hacer esto kludge a versiones más nuevas), .pyc-2.0 para 2.0, .pyc-2.2 para 2.2, y así sucesivamente (o equivalente .pyo-X.Y por supuesto). He oído que esto pronto va a desaparecer por fin (gracias Thomas! -), pero nos mareó semi-decentemente sobre este problema cosquilloso durante muchos, muchos años.

Una solución mucho más simple es mantener una sola versión de Python, si eso es factible para su sistema; Si su sistema tiene alguna complicación que lo haga inviable de tener una sola versión de Python (como la nuestra, y lo hace), entonces en estos días recomiendo encarecidamente virtualenv, que ya he mencionado.

+0

A veces las personas intentan distribuir archivos .pyc sin archivos .py como una forma de protección de IP. –

+0

@gnibbler: Sí, pero eso es estúpido, ya que los archivos .pyc son muy legibles y fáciles de descompilar para una representación muy cercana – nosklo

+0

Gracias por eso. Estoy sorprendido por el error de bloqueo de archivos. Eso significa que no puedo actualizar desde Python 2.5 a 2.6 un servidor a la vez, pero tengo que bajarlos y actualizarlos todos antes de volverlos a subir. – pwdyson

2

La versión de Python que crea el archivo se almacena en el archivo .pyc. lo general, esto significa que el .pyc se sustituye por uno con la versión correcta de Python

algunas razones esto podría no suceder
- Permisos
- archivo .py no está disponible

En el caso del problema de permisos , Python sólo tiene que utilizar el .py e ignorar el .pyc (a un costo de rendimiento)

Creo que está bien entre las versiones de menor importancia, sin embargo, por ejemplo, un Python2.6.2 .pyc debe trabajar con Python2.6.4

Aquí está un extracto de/share/archivos/usr/magia

# python: file(1) magic for python 
0 string  """ a python script text executable 
0 belong  0x994e0d0a python 1.5/1.6 byte-compiled 
0 belong  0x87c60d0a python 2.0 byte-compiled 
0 belong  0x2aeb0d0a python 2.1 byte-compiled 
0 belong  0x2ded0d0a python 2.2 byte-compiled 
0 belong  0x3bf20d0a python 2.3 byte-compiled 
0 belong  0x6df20d0a python 2.4 byte-compiled 
0 belong  0xb3f20d0a python 2.5 byte-compiled 
0 belong  0xd1f20d0a python 2.6 byte-compiled 

Así se puede ver que la versión correcta de Python está indicada por los primeros 4 bytes del archivo .pyc

+0

Eso significa que su .py no está disponible. – nosklo

0

que sin duda va a necesitar para recompilar los archivos de bytecode para que sean de alguna utilidad. El número mágico de bytecode ha cambiado en todas las versiones principales de Python (*).

Sin embargo, tener archivos de bytecode que no coincidan con la versión nunca debería colisionar con Python. Por lo general, simplemente ignorará cualquier bytecode que no tenga el número de versión correcto, por lo que no debería haber un error, será más lento la primera vez que recompila (o más lento cada vez que el usuario que ejecuta los scripts no lo haga) no tiene permiso de escritura para actualizar el bytecode).

(*:.. Y, a menudo durante las fases de desarrollo, además de en versiones anteriores a veces se cambia con respecto a versiones menores también ver import.c para una lista completa de los números mágicos y sus correspondientes versiones de Python)

5

Si tiene el código fuente, entonces lo recompilará. Entonces, en general, estás bien.

Pero esto podría ser malo para usted si los usuarios con versiones diferentes de Python se ejecutan desde un directorio de instalación central.

También podría ser malo si solo tiene los archivos pyc. Acabo de hacer una prueba rápida para ti. Creé dos archivos .pyc. Uno en 2.5 y uno en 2.6. El 2.5 no se ejecutará en 2.6 y el 2.6 no se ejecutará en 2.5. Ambos lanzan el error "ImportError: Bad magic number in ..", que tiene sentido porque el número mágico ha cambiado de 2.5 a 2.6.

Si desea determinar esto antes de tiempo se puede obtener el número mágico de su pitón de la siguiente manera:

$ python -V 
Python 2.6.2 
# python 
>>> import imp 
>>> imp.get_magic().encode('hex') 
'd1f20d0a' 

Para obtener el número mágico para un archivo pyc se puede hacer lo siguiente:

>>> f = open('test25.pyc') 
>>> magic = f.read(4) 
>>> magic.encode('hex') 
'b3f20d0a' 
>>> f = open('test26.pyc') 
>>> magic = f.read(4) 
>>> magic.encode('hex') 
'd1f20d0a' 
+0

¿Podría ampliar esto? Porque esa era la situación: "Pero esto podría ser malo para usted si los usuarios con versiones diferentes de Python se ejecutan desde un repositorio de código central". – pwdyson

+0

Ciertamente. Si primero suponemos que una persona con Python 2.5 ha usado el repositorio, las pycs serán 2.5 pycs. Cuando una persona con Python 2.6 usa el repositorio, convertirá las pycs de los archivos que importan a 2.6 pycs. También tomarán el golpe de velocidad por hacerlo. También puede tener problemas si las personas con diferentes versiones intentan usar las pycs al mismo tiempo. Para que quede claro, este repositorio del que hablo es donde las personas ejecutan el código de no verificar el código de entrada y salida. –

+0

Edité mi respuesta original y cambié el término "repositorio" por "dir de instalación" para asegurarme de que estaba libre. –

Cuestiones relacionadas