dis no Python: entenda o bytecode

Publicado em: 27/08/2026
Tempo de leitura: 8 minutos
A laptop screen showing a code editor with visible programming code in a dimly lit environment.

O módulo dis desmonta code objects do Python e mostra as instruções de bytecode executadas pelo interpretador. Ele ajuda a estudar como expressões, funções, loops, comprehensions, exceções e chamadas são compiladas. Também é útil para depuração de ferramentas, ensino, análise de desempenho e investigação de diferenças entre versões.

Bytecode é um detalhe de implementação. Instruções, argumentos, offsets, caches e otimizações podem mudar entre releases, inclusive versões menores. Não escreva lógica de negócio, formato persistente ou ferramenta de segurança que dependa rigidamente de uma sequência específica sem limitar e testar a versão do Python.

Desmonte uma função

dis.dis() aceita funções, métodos, classes, módulos, strings de código e code objects.

import dis


def somar(a, b):
    return a + b


dis.dis(somar)

A saída mostra offsets, instruções, argumentos e representações úteis dos operandos.

Compile uma expressão

Também é possível estudar código compilado dinamicamente.

codigo = compile("resultado = x * 2", "exemplo.py", "exec")
dis.dis(codigo)

compile() não executa o código, mas o conteúdo ainda deve ser tratado como não confiável se veio de outra pessoa.

Code objects

Funções possuem um atributo __code__ com bytecode, constantes, nomes, variáveis e metadados.

code = somar.__code__
print(code.co_varnames)
print(code.co_consts)
print(code.co_names)

Esses campos são voltados a introspecção e podem evoluir.

Instruções com get_instructions

dis.get_instructions() retorna objetos Instruction, melhores para análise programática que o texto de dis().

for instrucao in dis.get_instructions(somar):
    print(
        instrucao.offset,
        instrucao.opname,
        instrucao.arg,
        instrucao.argval,
    )

Prefira campos nomeados em vez de fazer parsing da saída formatada.

Instruction

Um objeto de instrução pode conter nome do opcode, argumento numérico, valor resolvido, representação, offset, posição de origem e marcadores de jump target.

Nem todo campo tem significado para todo opcode. Trate valores ausentes.

Bytecode

A classe dis.Bytecode oferece uma interface iterável e métodos de formatação.

bytecode = dis.Bytecode(somar)
for instrucao in bytecode:
    print(instrucao.opname)

print(bytecode.dis())

É útil quando a ferramenta precisa guardar o objeto analisado e opções de visualização.

Linhas e posições

As instruções podem ser associadas a linhas e intervalos do código-fonte. Python moderno mantém metadados de posição mais detalhados.

Use esses dados para diagnósticos, mas aceite posições ausentes em código gerado ou transformado.

show_offsets

Opções atuais de desmontagem podem mostrar offsets explicitamente. Eles ajudam a interpretar jumps e exception tables.

Offsets não devem ser comparados entre versões ou builds como se fossem IDs estáveis.

Instruções de carga

Operações como carregar constantes, nomes, globals, locals e atributos aparecem com opcodes específicos.

A escolha exata depende de escopo e otimizações. Compare:

x = 10

def usar_global():
    return x


def usar_local(x):
    return x

O bytecode ajuda a visualizar a diferença, mas não deve substituir o entendimento de escopo da linguagem.

Operações binárias

Expressões aritméticas são compiladas em instruções que carregam operandos e aplicam uma operação.

def calcular(a, b):
    return (a + b) * 2

Em versões modernas, várias operações podem compartilhar um opcode com argumento que indica a operação concreta.

Constantes dobradas

O compilador pode calcular expressões constantes antecipadamente.

def exemplo():
    return 2 + 3

A desmontagem pode mostrar apenas a constante final. Não conclua que toda expressão aparentemente constante será sempre dobrada.

Loops

Um for normalmente envolve obtenção do iterator, leitura do próximo item e jumps.

def totalizar(itens):
    total = 0
    for item in itens:
        total += item
    return total

Estudar o fluxo ajuda no ensino de iterators e controle, mas otimizações podem alterar a forma.

Condições e jumps

if, while, expressões booleanas e short-circuit usam instruções de jump.

O atributo is_jump_target identifica instruções que recebem desvios.

for instrucao in dis.get_instructions(funcao):
    if instrucao.is_jump_target:
        print("alvo", instrucao.offset)

Jumps relativos

A representação de jumps e offsets mudou em versões recentes. Use argval e APIs do módulo, não cálculos manuais baseados em bytes históricos.

Ferramentas devem declarar as versões suportadas.

Chamadas de função

Chamadas envolvem carregamento do callable, argumentos e instruções específicas de preparação e execução.

O bytecode pode mudar conforme chamadas posicionais, keyword arguments, métodos e otimizações adaptativas.

Comprehensions

List, set e dict comprehensions podem gerar code objects internos.

def pares(valores):
    return [x * 2 for x in valores if x % 2 == 0]

dis.dis() também desmonta code objects aninhados em muitos casos, permitindo ver a função implícita.

Generators

Funções com yield possuem instruções e flags específicas para suspensão e retomada.

Não use a desmontagem para alterar diretamente o estado de um generator. Use APIs públicas.

async e await

Coroutines e generators assíncronos geram bytecode próprio para espera, envio e retomada.

A forma varia bastante entre versões; use para estudo da versão em execução.

Exceções

Tratamento de exceções utiliza metadados e instruções que mudaram significativamente na evolução do CPython.

Não tente encontrar blocos try apenas procurando opcodes históricos. Use as APIs e metadados atuais.

Exception tables

Code objects modernos podem manter tabelas compactas de tratamento em vez de instruções explícitas no fluxo principal.

A saída do dis apresenta informações úteis, mas o formato interno não é contrato de estabilidade.

Adaptive interpreter

CPython pode especializar instruções durante a execução com base nos tipos observados. Isso melhora desempenho sem alterar o código-fonte.

A desmontagem padrão pode mostrar bytecode original ou adaptado conforme opções e estado da função.

adaptive

As APIs atuais oferecem opções para exibir instruções especializadas quando disponíveis.

dis.dis(funcao, adaptive=True)

Execute a função várias vezes antes se quiser observar especialização, mas não presuma que ela ocorrerá de maneira idêntica em todas as máquinas.

show_caches

Inline caches podem aparecer com show_caches=True.

dis.dis(funcao, show_caches=True)

Esses caches são internals de desempenho. Não os modifique e não baseie decisões funcionais neles.

Bytecode muda em runtime

A especialização pode alterar a forma observada depois de warm-up. Uma ferramenta que compara desmontagens precisa controlar se mostra código adaptativo.

Registre versão do Python, opções e quantidade de execuções.

stack_effect

dis.stack_effect(opcode, oparg) calcula o efeito de uma instrução na pilha de avaliação.

import dis
import opcode

efeito = dis.stack_effect(opcode.opmap["LOAD_CONST"], 0)
print(efeito)

Para jumps condicionais, a API pode aceitar informação sobre o ramo considerado.

Análise da pilha

Somar efeitos linearmente não basta em um grafo com jumps. Uma análise correta propaga alturas por blocos de controle e verifica convergência.

Use ferramentas especializadas quando precisar validar bytecode.

opcode

O módulo opcode fornece mapas e categorias de opcodes.

import opcode

print(opcode.opmap.get("RETURN_VALUE"))

Os números mudam entre versões. Use nomes e mapas da versão atual.

Comparação de implementações

dis descreve bytecode do runtime compatível com sua API, principalmente CPython. Outras implementações podem ter representação diferente.

Não generalize conclusões de CPython para toda a linguagem Python.

Otimização

Bytecode pode revelar alocação de comprehensions, loads repetidos e chamadas dentro de loops. Ainda assim, não otimize apenas pela aparência.

Meça com timeit, cProfile e workloads reais. Uma instrução a menos pode não produzir ganho relevante.

Microbenchmarks

Comparar duas formas de código exige warm-up, repetição, isolamento e controle de ruído.

O interpretador adaptativo torna ainda mais importante medir estado estável.

Segurança

Encontrar um opcode não prova que o código é seguro ou perigoso. Aliases, imports, objetos e comportamento dinâmico escapam de uma allowlist simples.

Não crie sandbox validando bytecode e depois chamando exec(). Use isolamento de processo e uma linguagem restrita.

Code objects não confiáveis

Não carregue code objects de marshal ou pickle não confiável para desmontar no mesmo processo crítico.

Mesmo que você não execute explicitamente, parsers e estruturas internas não devem ser expostos sem limites a payload hostil.

Ferramentas de diff

Para comparar versões, normalize offsets, caches e campos instáveis. Compare opnames e argumentos sem exigir identidade byte a byte.

Separe mudanças semânticas de diferenças de implementação.

CLI

O módulo pode desmontar arquivos pela linha de comando.

python -m dis modulo.py

É útil para aprendizado e inspeção rápida.

Integração com AST

A AST mostra estrutura de alto nível; dis mostra instruções após compilação. Comparar as duas camadas ajuda a entender otimizações.

Veja ast no Python.

Integração com tokenize

tokenize preserva comentários e grafia, que não aparecem no bytecode.

O artigo sobre tokenize no Python explica a camada lexical.

Testes de ferramentas

Execute a suíte em cada versão suportada. Inclua funções simples, closures, generators, async, comprehensions, exceções e pattern matching.

Use fixtures por versão quando a saída esperada depende de opcodes.

Erros comuns

Os erros mais frequentes são assumir opcodes estáveis, fazer parsing do texto do dis, comparar offsets entre versões, ignorar caches adaptativos, otimizar sem medir, tratar bytecode como sandbox, generalizar CPython para outras implementações e carregar code objects não confiáveis.

Conclusão

dis permite observar como o Python compila e executa funções no nível do bytecode. Use get_instructions() para análise programática, controle opções de caches e especialização e sempre registre a versão do runtime.

Trate o bytecode como detalhe mutável e use profiling antes de otimizar. Consulte a documentação oficial de dis e a documentação de opcode.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Flat lay of gold bitcoin coins on a pink surface, symbolizing cryptocurrency and modern investment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tokenize no Python: leia tokens do código

    Aprenda tokenize no Python para ler tokens, comentários, encoding, indentação e posições, além de transformar e reconstruir código com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    27/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

    zipapp no Python: crie arquivos .pyz

    Aprenda zipapp no Python para criar arquivos .pyz, definir entry points, incluir dependências, usar recursos e distribuir CLIs com segurança.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sysconfig no Python: caminhos e build

    Aprenda sysconfig no Python para descobrir paths, schemes, headers, flags de build, ABI, extensões nativas e detalhes de ambientes virtuais.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    A person typing on a laptop with a Python programming book visible, capturing technology and learning.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    marshal no Python: formato interno

    Aprenda marshal no Python para objetos internos e bytecode, entenda versões, allow_code, limites, caches e riscos de dados não confiáveis.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    A close-up view of fresh, green cucumbers ready for pickling and preservation in Estonia.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    copyreg no Python: personalize o pickle

    Aprenda copyreg no Python para personalizar pickle, registrar redutores, versionar estado, evitar conflitos globais e serializar com segurança.

    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 Avançado
    Foto de perfil de Leandro Hirt da Academify

    reprlib no Python: representações seguras

    Aprenda reprlib no Python para resumir listas, strings e objetos recursivos, limitar logs e criar representações seguras e legíveis.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026