compileall en Python: genera bytecode .pyc

Publicado el: 27/08/2026
Tempo de leitura: 7 minutos
A developer typing code on a laptop with a Python book beside in an office.

El módulo compileall compila archivos fuente Python de un directorio o árbol completo en bytecode .pyc. Es útil en pipelines de build, imágenes de containers, paquetes de sistema, despliegues offline, validación de sintaxis y entornos read-only donde la primera importación no debería crear caches.

El módulo no convierte Python en un ejecutable independiente y no protege el código. El bytecode depende de una implementación y versión compatible, puede inspeccionarse y normalmente actúa como cache de importación. Usa compileall para preparación operativa y verificación, no para secreto.

Compila un directorio

compile_dir() recorre un directorio y compila archivos reconocidos.

import compileall

exito = compileall.compile_dir(
    "mi_paquete",
    quiet=1,
)
print(exito)

El resultado general indica si todas las compilaciones solicitadas terminaron correctamente. En un build, trata False como fallo.

Compila un archivo

compile_file() procesa un path individual.

compileall.compile_file(
    "mi_paquete/modulo.py",
    quiet=1,
)

Para control de bajo nivel sobre un único archivo, utiliza py_compile, que se aborda en el siguiente artículo.

Usa la línea de comandos

El módulo ofrece una CLI.

python -m compileall mi_paquete

Es cómoda en Dockerfiles y CI. Comprueba el exit code y no dependas solo del texto impreso.

Dónde se guardan los .pyc

Python moderno normalmente escribe caches en directorios __pycache__, con nombres que incluyen la tag del intérprete y el nivel de optimización.

mi_paquete/__pycache__/modulo.cpython-314.pyc

Así pueden coexistir caches de varias versiones y optimizaciones.

Layout legacy

Con legacy=True, los archivos compilados se escriben junto al fuente con la convención antigua.

Evita este modo salvo que una herramienta legacy lo exija. __pycache__ es el layout normal del sistema de importación moderno.

Fuerza recompilación

force=True compila aunque el cache parezca actualizado.

compileall.compile_dir(
    "mi_paquete",
    force=True,
    quiet=1,
)

Es útil para builds reproducibles y cambios de política, pero aumenta tiempo y escrituras.

Validación de sintaxis

Compilar un árbol detecta SyntaxError, indentación inválida y ciertas incompatibilidades de versión sin ejecutar el cuerpo de los módulos.

Es una comprobación rápida, pero no sustituye tests, imports reales, type checking o linting.

La compilación no ejecuta módulos

El compilador analiza y crea code objects. No ejecuta imports, decorators, llamadas de nivel superior o inicialización de clases.

Un módulo puede compilar y fallar al importar por dependencia ausente, variable de entorno, error de runtime o extensión incompatible.

Recursión de directorios

compile_dir() permite limitar profundidad.

compileall.compile_dir(
    "src",
    maxlevels=5,
    quiet=1,
)

Define límites cuando la raíz contiene mounts, árboles generados o enlaces inesperados.

Enlaces simbólicos

Evalúa su comportamiento en el entorno real. Un árbol de build puede contener symlinks que salen de la raíz o duplican directorios.

Compila raíces confiables explícitas y nunca aceptes un path arbitrario sin validación.

Excluye paths con rx

El parámetro rx acepta una expresión regular.

import re

compileall.compile_dir(
    "proyecto",
    rx=re.compile(r"/(tests|vendor)/"),
    quiet=1,
)

Prueba la expresión en Windows y Unix porque los separadores varían.

Salida quiet

quiet controla mensajes normales. La automatización puede reducir ruido conservando errores.

El silencio no sustituye observabilidad. Registra duración, cantidad de archivos, versión y resultado.

Workers paralelos

workers compila varios archivos concurrentemente.

compileall.compile_dir(
    "src",
    workers=4,
    quiet=1,
)

Elige un límite acorde a CPU, filesystem y runner. Más workers pueden empeorar el rendimiento en storage lento.

Cantidad automática de workers

Versiones compatibles pueden aceptar valores especiales que calculan workers según el sistema. Verifica la documentación de tu intérprete.

Un límite explícito suele ser más predecible.

Niveles de optimización

optimize selecciona compilación normal, -O o -OO. APIs recientes pueden aceptar varios niveles.

compileall.compile_dir(
    "src",
    optimize=[0, 1, 2],
    quiet=1,
)

Esto puede crear varios caches por fuente.

Qué cambia -O

El modo optimizado elimina asserts y hace falso __debug__. -OO también puede eliminar docstrings.

Nunca uses assert para validar entrada, autorización o invariantes críticas de producción.

Cuando varios niveles generan datos idénticos, hardlink_dupes puede ahorrar espacio mediante hard links.

Prueba en containers, volúmenes, package builders y backups, porque soporte y semántica varían.

Modos de invalidación

Un .pyc utiliza una política basada en timestamps o hashes.

Los builds reproducibles suelen preferir hash para no depender de mtimes variables. Usa py_compile.PycInvalidationMode desde la API.

Timestamp frente a hash

Timestamp es rápido y común, pero depende de tamaño y modificación. Hash incorpora la identidad del contenido y encaja mejor en artefactos herméticos.

Elige una política consistente con instalación e importación.

SOURCE_DATE_EPOCH

Los sistemas de build reproducible pueden definir SOURCE_DATE_EPOCH, afectando defaults determinísticos.

No es suficiente por sí solo: controla orden, paths embebidos, permisos y versión del intérprete.

Filenames embebidos

Los code objects conservan filenames mostrados en tracebacks. Un path absoluto del runner puede filtrar infraestructura y no existir en destino.

Transforma paths para que correspondan al layout instalado.

stripdir

stripdir elimina un prefijo del filename guardado.

compileall.compile_dir(
    "/build/work/src",
    stripdir="/build/work",
    quiet=1,
)

Comprueba que el prefijo coincida e inspecciona los tracebacks.

prependdir

prependdir agrega un prefijo después.

compileall.compile_dir(
    "/build/work/src",
    stripdir="/build/work/src",
    prependdir="/opt/app",
    quiet=1,
)

Así los filenames compilados apuntan al layout final.

Parámetros históricos

Existen opciones antiguas de directorio para compatibilidad. Prefiere strip y prepend actuales y documenta la versión mínima.

No combines opciones incompatibles sin comprobar la firma activa.

Builds en containers

Compila después de copiar el código, usando el mismo Python que ejecutará la aplicación.

RUN python -m compileall -q /opt/app

Compilar en una versión y ejecutar otra produce caches ignorados o incompatibles.

No copies caches locales

Los caches de desarrollo pueden usar otra versión, optimización, paths o invalidación.

Ignora __pycache__ en Git y genera bytecode en el build final.

Despliegues read-only

La precompilación ayuda cuando el directorio será read-only y el usuario de runtime no puede crear caches.

Confirma que todos los fuentes necesarios fueron compilados y que la versión coincide.

Permisos

El usuario de build necesita leer fuente y crear directorios. Ajusta ownership para el usuario de ejecución.

No ejecutes la aplicación como root solo para crear bytecode.

Paquetes instalados

Los instaladores pueden compilar automáticamente. Evita duplicar trabajo sin motivo.

Usa compileall explícitamente para validación, optimización, reproducibilidad o imágenes read-only.

Namespace packages

Los namespace packages pueden abarcar varias raíces. Compila cada directorio instalado.

La compilación no valida la composición del namespace en runtime.

Errores de lectura

Archivos sin permiso, paths rotos y encoding inválido pueden fallar. Conserva el diagnóstico y falla el build si el código requerido no compila.

No ignores un resultado falso porque la mayoría de caches existan.

Fuente generada

Genera el código antes de compileall. Si un paso posterior cambia fuentes, el cache queda antiguo o se recompila al importar.

Ordena el pipeline: generación, formato, validación, compilación y packaging.

Entrada no confiable

No compiles árboles subidos por usuarios en el proceso principal. El parser consume recursos y links o mounts pueden escapar de límites.

Usa worker aislado, directorio temporal y límites estrictos.

El bytecode no es secreto

Distribuir solo .pyc dificulta lectura casual, pero herramientas inspeccionan constantes, nombres e instrucciones.

No guardes secretos en código ni prometas protección intelectual fuerte.

Compatibilidad

El formato cambia entre versiones. Un .pyc contiene un magic number y normalmente se rechaza en intérpretes incompatibles.

Compila con la misma implementación y major/minor del runtime.

Inspecciona con dis

dis muestra instrucciones y permite comparar optimizaciones.

Consulta dis en Python.

Valida imports

Después de compilar, ejecuta smoke tests de importación en entorno limpio.

python -c "import mi_paquete"

Ejemplo de CI

python -m compileall -q -f src
pytest

Usa la versión declarada por el proyecto.

Limpieza

Elimina caches antiguos borrando directorios __pycache__ dentro de una raíz validada.

No hagas borrado recursivo desde paths no comprobados ni sigas enlaces externos.

Prueba el build

Prueba árbol vacío, SyntaxError, archivo sin permiso, varios niveles, filenames transformados, ejecución read-only e imports en destino.

Compara hashes si la reproducibilidad es requisito.

Errores comunes

Los fallos frecuentes son tratar bytecode como ejecutable, compilar con otra versión, ignorar retorno falso, copiar caches locales, depender de asserts, embutir paths del runner, compilar antes de finalizar fuentes y creer que .pyc protege el código.

Conclusión

compileall prepara árboles Python para importación, valida sintaxis y controla optimización, concurrencia, filenames e invalidación. Ejecútalo en el build con el mismo intérprete de producción y trata cada fallo como problema del artefacto.

Genera caches en entorno limpio, conserva tracebacks útiles y valida imports después. Consulta la documentación oficial de compileall y sysconfig en Python para detalles del build.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Vivid close-up of code on a computer screen showcasing programming details.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    codeop en Python: compila entrada interactiva

    Aprende codeop en Python para detectar comandos completos, incompletos o inválidos, crear REPLs y conservar flags de __future__ de forma

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    linecache en Python: lee líneas del código

    Aprende linecache en Python para recuperar líneas de código, actualizar cache, soportar tracebacks y loaders, conservar indentación y proteger rutas.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    faulthandler en Python: diagnostica fallos

    Aprende faulthandler en Python para diagnosticar crashes, deadlocks, señales fatales, timeouts y bloqueos con dumps de todas las threads.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A detailed image of a reticulated python showcasing its patterned scales and intricate skin texture.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    symtable en Python: analiza scopes

    Aprende symtable en Python para analizar scopes, locals, globals, parámetros, imports, nonlocals, closures y namespaces del compilador.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    Detailed shot of a Jungle Carpet Python (Morelia spilota cheynei) in its natural habitat.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    dis en Python: entiende el bytecode

    Aprende dis en Python para inspeccionar bytecode, jumps, stack effects, caches adaptativos y optimizaciones sin depender de internals inestables.

    Ler mais

    Tempo de leitura: 5 minutos
    27/08/2026
    Gold Bitcoin coins displayed on a sparkling gold texture, representing digital currency and finance.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tokenize en Python: lee tokens del código

    Aprende tokenize en Python para leer tokens, comentarios, encoding, indentación y posiciones, además de transformar y reconstruir código con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    27/08/2026