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

    Código em monitor representando acesso a memória nativa com ctypes.memoryview_at no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ctypes.memoryview_at: acesse memória sem cópias

    Aprenda ctypes.memoryview_at no Python para acessar memória nativa sem cópias, validar ponteiros e evitar erros perigosos.

    Ler mais

    Tempo de leitura: 7 minutos
    12/10/2026
    Código Python em tela representando EnumDict e enumerações avançadas
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    EnumDict: personalize Enums com validação

    Aprenda EnumDict no Python para personalizar EnumType, validar membros e criar enumerações avançadas com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Rack de servidores representando balanceamento de conexões com SO_REUSEPORT_LB no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: distribua conexões entre workers

    Aprenda SO_REUSEPORT_LB no Python para distribuir conexões entre múltiplos workers com segurança, testes e portabilidade.

    Ler mais

    Tempo de leitura: 6 minutos
    11/10/2026
    Código Python assíncrono em notebook para inspect.markcoroutinefunction
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: identifique wrappers async

    Aprenda inspect.markcoroutinefunction no Python para identificar wrappers assíncronos, integrar frameworks e evitar detecção incorreta de corrotinas.

    Ler mais

    Tempo de leitura: 6 minutos
    10/10/2026
    Código Python para percorrer pastas e arquivos com Path.walk
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: percorra diretórios com segurança

    Aprenda Path.walk no Python para percorrer diretórios, filtrar arquivos, tratar erros e controlar a travessia com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    10/10/2026
    Depuração de processo Python em terminal com código
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: depure processos Python em execução

    Aprenda a anexar o pdb a um processo Python em execução, inspecionar pilhas e diagnosticar travamentos com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026