py_compile no Python: gere arquivos pyc

Publicado em: 04/08/2026
Tempo de leitura: 7 minutos
Monitor com código binário representando geração de arquivos pyc com py_compile no Python

Quando um módulo Python é importado, o interpretador pode armazenar seu bytecode em um arquivo .pyc dentro de __pycache__. O módulo py_compile no Python permite gerar esse cache antecipadamente, validar arquivos durante builds e controlar como o interpretador decide se o bytecode ainda corresponde ao código-fonte.

Neste guia, você aprenderá a usar py_compile.compile(), tratar PyCompileError, escolher otimização e configurar invalidação por timestamp ou hash. O conteúdo complementa nossos artigos sobre bytecode com dis, compileall, tracebacks, tokenize e compilação interativa.

O que é um arquivo pyc

Um arquivo .pyc contém bytecode serializado e um cabeçalho com informações usadas para validar o cache. Ele evita recompilar o mesmo código-fonte em determinadas inicializações, mas não transforma Python em um binário independente.

O bytecode continua específico da implementação e da versão. Um arquivo produzido por uma versão do CPython normalmente não deve ser reutilizado por outra tag de cache.

Compilar um arquivo

A função principal recebe o caminho do arquivo-fonte.

import py_compile

caminho = py_compile.compile("meu_modulo.py")
print(caminho)

Por padrão, o resultado segue as convenções PEP 3147 e PEP 488, normalmente dentro de __pycache__ com a tag do interpretador.

Validar sintaxe durante o build

Compilar previamente é uma maneira simples de detectar SyntaxError antes da implantação.

from pathlib import Path
import py_compile

for arquivo in Path("src").rglob("*.py"):
    py_compile.compile(
        str(arquivo),
        doraise=True,
    )

Para árvores inteiras, o módulo compileall oferece uma interface mais conveniente. py_compile é adequado quando a aplicação já possui a lista exata de arquivos.

doraise e PyCompileError

Por padrão, um erro é escrito em stderr e a função retorna None. Com doraise=True, a falha gera PyCompileError.

try:
    py_compile.compile(
        "quebrado.py",
        doraise=True,
    )
except py_compile.PyCompileError as erro:
    print("Compilação falhou:", erro)

Aplicações e pipelines devem preferir a exceção, pois ela permite controlar o status e produzir relatórios estruturados.

Definir o destino com cfile

cfile escolhe explicitamente o arquivo de saída.

py_compile.compile(
    "modulo.py",
    cfile="build/modulo.pyc",
    doraise=True,
)

Crie o diretório de destino antes. Um caminho personalizado pode ser útil em empacotamento, mas as convenções padrão facilitam importação e coexistência entre versões.

Se o destino calculado for um link simbólico ou um arquivo não regular, a função lança FileExistsError.

A documentação oficial de py_compile explica que a gravação segue a semântica de importlib, com escrita temporária e renomeação para reduzir problemas de concorrência. A proteção evita substituir silenciosamente objetos especiais.

Nome de arquivo nos tracebacks

dfile define o nome que aparecerá em tracebacks e mensagens relacionados ao objeto compilado.

py_compile.compile(
    "src/pacote/modulo.py",
    dfile="/app/pacote/modulo.py",
    doraise=True,
)

Isso é útil quando o caminho no ambiente de build difere do caminho de implantação. Use uma localização significativa e não exponha diretórios secretos.

Nível de otimização

optimize é passado ao built-in compile(). O padrão -1 utiliza o nível do interpretador atual.

py_compile.compile(
    "modulo.py",
    optimize=1,
    doraise=True,
)

O nível 1 remove asserts e altera __debug__. O nível 2 também remove docstrings em muitos contextos. Não use otimização para esconder código nem presuma ganho significativo sem medir.

Arquivos diferentes por otimização

A tag do cache inclui a variante de otimização quando o destino padrão é usado. Isso permite que caches de níveis diferentes coexistam em __pycache__.

Ao escolher cfile manualmente, não sobrescreva acidentalmente variantes necessárias. Registre versão, implementação e otimização no processo de build.

Modos de invalidação

PycInvalidationMode controla como o interpretador verifica se um .pyc está atualizado.

  • TIMESTAMP: compara timestamp e tamanho;
  • CHECKED_HASH: armazena hash e compara com o conteúdo;
  • UNCHECKED_HASH: armazena hash, mas confia que um sistema externo mantém o cache.

O modo fica registrado no cabeçalho do arquivo.

Invalidação por timestamp

from py_compile import PycInvalidationMode

py_compile.compile(
    "modulo.py",
    doraise=True,
    invalidation_mode=PycInvalidationMode.TIMESTAMP,
)

É rápido e padrão quando SOURCE_DATE_EPOCH não está definido. Filesystems com resolução de tempo limitada podem criar casos em que conteúdo muda, mas metadados parecem equivalentes.

Hash verificado

py_compile.compile(
    "modulo.py",
    doraise=True,
    invalidation_mode=PycInvalidationMode.CHECKED_HASH,
)

O interpretador calcula novamente o hash da fonte durante a importação. Esse modo melhora determinismo e evita depender somente de timestamps, com custo adicional de leitura e hashing.

Hash não verificado

py_compile.compile(
    "modulo.py",
    doraise=True,
    invalidation_mode=PycInvalidationMode.UNCHECKED_HASH,
)

Nesse modo, o runtime assume que o arquivo está correto. Use somente quando um gerenciador de pacotes ou build system controla rigorosamente a atualização dos caches.

SOURCE_DATE_EPOCH

Quando a variável SOURCE_DATE_EPOCH está presente, o padrão do modo de invalidação passa a ser CHECKED_HASH. Isso ajuda builds reproduzíveis que não querem depender do horário real.

Desde Python 3.7.2, a variável determina o padrão, mas não substitui um argumento explícito.

quiet

quiet controla mensagens quando doraise=False.

  • 0 ou 1: comportamento normal de diagnóstico;
  • 2: nenhuma mensagem e doraise deixa de ter efeito.

Em código de automação, prefira doraise=True e captura de exceção em vez de silenciar completamente a falha.

Interface de linha de comando

O módulo pode compilar arquivos informados explicitamente.

python -m py_compile arquivo1.py arquivo2.py

Ele não procura recursivamente por fontes. O status de saída é diferente de zero se algum arquivo não puder ser compilado.

Ler caminhos da entrada padrão

Quando - é o único argumento, os nomes dos arquivos são lidos de stdin.

find src -name '*.py' -print | python -m py_compile -

Caminhos com newline são raros, mas possíveis em sistemas Unix. Para pipelines rigorosos, use uma integração Python que percorra Path diretamente.

Modo quiet na CLI

python -m py_compile -q arquivo1.py arquivo2.py

A opção reduz mensagens, mas o código de saída ainda deve ser verificado pelo pipeline.

Permissões e instalação compartilhada

A compilação antecipada é útil quando usuários finais podem ler o pacote, mas não possuem permissão para gravar em __pycache__.

O processo de instalação executado com privilégios adequados cria os caches. Depois, permissões devem permitir leitura sem conceder escrita desnecessária.

Concorrência

A escrita usa arquivo temporário e renomeação, o que reduz resultados parciais quando vários processos compilam o mesmo destino. Isso não elimina toda disputa de build nem torna seguro escolher o mesmo cfile para fontes diferentes.

Use diretórios separados por versão e evite builds concorrentes que escrevem no mesmo artefato personalizado.

pyc não protege o código

Bytecode pode ser inspecionado e desmontado. Distribuir apenas .pyc não fornece proteção forte de propriedade intelectual, assinatura ou criptografia.

Além disso, código não confiável continua perigoso quando importado, independentemente de estar em fonte ou bytecode.

Remover caches antigos

Não é necessário versionar __pycache__ na maioria dos projetos. Ao trocar interpretador ou criar um build limpo, remova caches e regenere.

from pathlib import Path

for pasta in Path(".").rglob("__pycache__"):
    for arquivo in pasta.iterdir():
        arquivo.unlink()
    pasta.rmdir()

Use ferramentas de limpeza com cuidado para não apagar ambientes compartilhados.

Exemplo de compilador controlado

from pathlib import Path
import py_compile


def compilar(arquivo: Path) -> Path:
    destino = py_compile.compile(
        str(arquivo),
        doraise=True,
        optimize=0,
        invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
    )
    return Path(destino)

O chamador pode registrar tamanho, hash do artefato e versão do Python.

Testes

Crie arquivos temporários válidos e inválidos e confirme destino, exceções e modo escolhido.

from tempfile import TemporaryDirectory

with TemporaryDirectory() as pasta:
    fonte = Path(pasta) / "ok.py"
    fonte.write_text("valor = 42\n", encoding="utf-8")
    pyc = compilar(fonte)
    assert pyc.exists()

Teste também symlink de destino em plataformas que oferecem suporte.

Erros frequentes

  • Presumir que pyc é portátil entre versões.
  • Ignorar o retorno None quando doraise=False.
  • Escolher um cfile compartilhado por várias fontes.
  • Usar hash não verificado sem build confiável.
  • Distribuir pyc como proteção do código.
  • Confundir compilação com execução de testes.
  • Não registrar o nível de otimização.
  • Versionar caches gerados localmente sem necessidade.

Boas práticas

  • Use doraise=True em automação.
  • Prefira o caminho padrão de __pycache__.
  • Escolha explicitamente o modo em builds reproduzíveis.
  • Separe artefatos por versão e otimização.
  • Compile antes da implantação para detectar sintaxe inválida.
  • Execute testes além da compilação.
  • Não importe bytecode não confiável.
  • Limpe caches ao trocar de ambiente.

Conclusão

O módulo py_compile no Python compila arquivos-fonte em caches .pyc, permitindo validar sintaxe e preparar instalações onde o runtime não pode escrever no diretório do pacote. Ele oferece controle sobre destino, nome em traceback, otimização e invalidação.

A escolha entre timestamp e hash depende do processo de build. Com exceções explícitas, caminhos padronizados e isolamento por versão, py_compile torna a geração de bytecode previsível sem confundir cache com binário portátil, proteção de código ou teste funcional.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    A vibrant collection of blue sewing threads arranged with hands on a white background.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    queue no Python: coordene threads

    Aprenda queue no Python para coordenar threads com FIFO, prioridade, backpressure, task_done, join, retries e shutdown seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    A male software engineer working on code in a modern office setting.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    struct no Python: trabalhe com binário

    Aprenda struct no Python para empacotar dados binários, controlar endianness, usar buffers e validar protocolos e arquivos externos.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tarfile no Python: crie TAR seguro

    Aprenda tarfile no Python para criar TAR comprimido, inspecionar membros e extrair com filtros, limites e proteção contra path traversal.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Row of colorful office binders neatly arranged on a shelf, ideal for organization concepts.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    gzip no Python: comprima arquivos .gz

    Aprenda gzip no Python para ler e gravar .gz, criar saídas reproduzíveis, trabalhar com streams e limitar a expansão de

    Ler mais

    Tempo de leitura: 4 minutos
    17/08/2026
    Color-coded office binders organized neatly in a storage shelf, featuring labels and a striking red binder.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    lzma no Python: comprima arquivos XZ

    Aprenda lzma no Python para criar arquivos XZ, usar streams, checks, filtros e limites de memória ao descompactar dados externos.

    Ler mais

    Tempo de leitura: 5 minutos
    17/08/2026
    Exquisite python skin handbag with intricate snake emblem and elegant design.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    bz2 no Python: comprima com bzip2

    Aprenda bz2 no Python para comprimir arquivos e bytes, processar fluxos em blocos e limitar a expansão de dados externos.

    Ler mais

    Tempo de leitura: 5 minutos
    16/08/2026