¿Cómo puedo generar manualmente un archivo .pyc a partir de un archivo .py

128

Por alguna razón, no puedo depender de la declaración de "importación" de Python para generar el archivo .pyc automáticamente

¿Hay alguna manera de implementar una función de la siguiente manera?

def py_to_pyc(py_filepath, pyc_filepath):
    ...
zJay
fuente

Respuestas:

241

Puedes usar compileallen la terminal. El siguiente comando irá recursivamente en subdirectorios y creará archivos pyc para todos los archivos python que encuentre. El módulo compileall es parte de la biblioteca estándar de python, por lo que no necesita instalar nada adicional para usarlo. Esto funciona exactamente de la misma manera para python2 y python3.

python -m compileall .
Marwan Alsabbagh
fuente
44
Esta debería ser la respuesta aceptada, al menos en mi necesidad de compilar todo * .py en * .pyc: recursivamente :)
swdev
1
¿Es posible distribuir un archivo PYC que contenga todas las bibliotecas utilizadas? Para que los usuarios no tengan que instalarlos, simplemente ejecutaron el archivo PYC, sé que en Java esto es posible usando un JAR. ¿Hay algún método similar para Python?
D.Snap
También escuché algo sobre metaarchivos en Python. Este compilatorio también construye algo de caché? Si no, ¿cuál es el comando para eso? Dado que los usuarios finales no tienen permiso de escritura en el directorio lib. Y quiero acelerar las cosas aquí ... PD. también eche un vistazo a la -Obandera, para la compilación de bytecode (.pyo file iso .pyc).
peligro89
¿Qué hay de descompilar?
Sajuuk
1
ten cuidado con este comando. Accidentalmente hice un compileallen mi carpeta de paquetes de sitio y lo estropeó todo
Alex
58

Puede compilar archivos individuales desde la línea de comandos con:

python -m compileall <file_1>.py <file_n>.py
tendencia
fuente
55

Ha pasado un tiempo desde la última vez que usé Python, pero creo que puedes usar py_compile:

import py_compile
py_compile.compile("file.py")
Mike Bailey
fuente
8
Probablemente desee incluir el segundo parámetro, que determina el archivo de salida. De lo contrario, el valor predeterminado es algo así __pycache__/file.cpython-32.pycy se obtiene como valor de retorno.
rvighne
46

Encontré varias formas de compilar scripts de python en bytecode

  1. Utilizando py_compileen terminal:

    python -m py_compile File1.py File2.py File3.py ...

    -m especifica el nombre del módulo (s) que se compilará.

    O, para la compilación interactiva de archivos

    python -m py_compile -
    File1.py
    File2.py
    File3.py
       .
       .
       .
  2. Utilizando py_compile.compile:

    import py_compile
    py_compile.compile('YourFileName.py')
  3. Utilizando py_compile.main():

    Compila varios archivos a la vez.

    import py_compile
    py_compile.main(['File1.py','File2.py','File3.py'])

    La lista puede crecer todo el tiempo que desee. Alternativamente, obviamente puede pasar una lista de archivos en los nombres de archivo principal o incluso en los argumentos de la línea de comandos.

    O, si pasa ['-']en main, puede compilar archivos interactivamente.

  4. Utilizando compileall.compile_dir():

    import compileall
    compileall.compile_dir(direname)

    Compila todos los archivos Python presentes en el directorio suministrado.

  5. Utilizando compileall.compile_file():

    import compileall
    compileall.compile_file('YourFileName.py')

Echa un vistazo a los enlaces a continuación:

https://docs.python.org/3/library/py_compile.html

https://docs.python.org/3/library/compileall.html

Abhishek Kashyap
fuente
Una pequeña corrección es que el nombre del módulo que está cargando es py_compiley compileallNO py_compile.pyo compileall.py. En otras palabras, debería ser python3 -m py_compile PYTHON_FILENAMEo python3 -m compileall PYTHON_FILES_DIRECTORY.
Devy
17

Yo usaría compileall . Funciona bien tanto desde scripts como desde la línea de comandos. Es un módulo / herramienta de nivel un poco más alto que la ya mencionada py_compile que también usa internamente.

Pekka Klärck
fuente
compileallno incluye lógica para omitir archivos para los que el .pycarchivo correspondiente ya está actualizado, ¿verdad?
Kyle Strand
2
@KyleStrand compileallomite archivos que ya tienen una versión actualizada .pyc(probado con Python 2.7.11)
Eponymous
@Eponymous Interesante. No estoy seguro de por qué pensé lo contrario. Gracias por revisar.
Kyle Strand
6

En Python2 podrías usar:

python -m compileall <pythonic-project-name>

lo que hace la compilación de toda .pya .pycen el proyecto que contiene las subcarpetas.


En Python3 podrías usar:

python3 -m compileall <pythonic-project-name>

lo que hace que compile todo .pyen las __pycache__carpetas del proyecto que contenían las subcarpetas.

O con el dorado de esta publicación :

Puede aplicar el mismo diseño de .pycarchivos en las carpetas que en Python2 usando:

python3 -m compileall -b <pythonic-project-name>

La opción -bactiva la salida de .pycarchivos a sus ubicaciones heredadas (es decir, lo mismo que en Python2).

Benyamin Jafari
fuente
3

Para que coincida con los requisitos de la pregunta original (ruta de origen y ruta de destino), el código debería ser así:

import py_compile
py_compile.compile(py_filepath, pyc_filepath)

Si el código de entrada tiene errores, se genera la excepción py_compile.PyCompileError .

ababak
fuente
1

Hay dos formas de hacer esto.

  1. Línea de comando
  2. Usando el programa python

Si está utilizando la línea de comando, use python -m compileall <argument>para compilar código python en código binario python. Ex:python -m compileall -x ./*

O bien, puede usar este código para compilar su biblioteca en código de bytes.

import compileall
import os

lib_path = "your_lib_path"
build_path = "your-dest_path"

compileall.compile_dir(lib_path, force=True, legacy=True)

def compile(cu_path):
    for file in os.listdir(cu_path):
        if os.path.isdir(os.path.join(cu_path, file)):
            compile(os.path.join(cu_path, file))
        elif file.endswith(".pyc"):
            dest = os.path.join(build_path, cu_path ,file)
            os.makedirs(os.path.dirname(dest), exist_ok=True)
            os.rename(os.path.join(cu_path, file), dest)

compile(lib_path)

mire ☞ docs.python.org para obtener documentación detallada

Prasante
fuente