code no Python: crie um REPL customizado

Publicado em: 12/08/2026
Tempo de leitura: 6 minutos
Terminal interativo representando um REPL customizado com o módulo code no Python

O módulo code no Python oferece as classes usadas para construir loops de leitura, avaliação e exibição, conhecidos como REPLs. Com InteractiveInterpreter e InteractiveConsole, uma aplicação pode fornecer um prompt Python embutido, controlar o namespace, capturar mensagens de erro e decidir como linhas incompletas serão acumuladas.

Esse recurso é valioso em ferramentas de ensino, depuradores, notebooks simplificados, consoles administrativos e ambientes de experimentação. Porém, ele executa código Python real. Não use um REPL embutido como sandbox para usuários não confiáveis: imports, sistema de arquivos, rede, processos e objetos já presentes no namespace podem ser explorados.

InteractiveInterpreter e InteractiveConsole

InteractiveInterpreter cuida da compilação, do estado do namespace e da execução, mas não implementa prompt nem buffering de várias linhas. InteractiveConsole herda essa base e adiciona comportamento parecido com o console padrão, incluindo os prompts principal e secundário.

from code import InteractiveConsole

console = InteractiveConsole()
console.interact(
    banner='Console de diagnóstico',
    exitmsg='Console encerrado',
)

Esse exemplo abre um REPL no processo atual. Tudo que o usuário executar terá as mesmas permissões do programa.

Definir um namespace controlado

O parâmetro locals recebe um mapeamento usado como namespace. Ele permite expor somente objetos específicos e preservar variáveis entre comandos.

from code import InteractiveConsole

contexto = {
    'status': lambda: {'fila': 4, 'saude': 'ok'},
    'versao': '2.1.0',
}
console = InteractiveConsole(locals=contexto)

Uma lista reduzida não transforma o console em ambiente seguro. O próprio Python oferece caminhos para introspecção e recuperação de objetos. Use esse controle para ergonomia e organização, não como fronteira contra atacantes.

Executar uma linha com runsource()

runsource() compila e executa uma string. O retorno informa se é necessária mais entrada: True significa comando incompleto; False significa que o comando foi executado ou rejeitado.

from code import InteractiveInterpreter

interp = InteractiveInterpreter()
precisa_mais = interp.runsource('for i in range(3):')
print(precisa_mais)  # True

Esse protocolo permite escolher entre um prompt principal e um prompt de continuação.

Acumular blocos com push()

InteractiveConsole.push() mantém um buffer interno. Cada linha é adicionada e o conjunto é compilado novamente.

from code import InteractiveConsole

console = InteractiveConsole()
print(console.push('def dobro(x):'))  # True
print(console.push('    return x * 2'))  # True
print(console.push(''))  # False
print(console.push('dobro(5)'))  # False

Quando o bloco termina ou é inválido, o buffer é limpo. resetbuffer() descarta manualmente uma entrada pendente, algo útil após cancelamento.

Detectar código incompleto

A função compile_command() tenta reproduzir a decisão do interpretador real. Ela devolve um objeto de código quando a entrada está completa, None quando falta conteúdo e lança SyntaxError quando existe um erro completo.

from code import compile_command

resultado = compile_command('if ativo:', symbol='single')
assert resultado is None

O módulo codeop no Python aprofunda o estado de compilação e flags de __future__ para consoles persistentes.

Personalizar a entrada

Subclasses de InteractiveConsole podem sobrescrever raw_input(). Isso permite ler linhas de uma interface gráfica, socket local, editor web ou fila interna.

class ConsoleFila(InteractiveConsole):
    def __init__(self, fila, **kwargs):
        super().__init__(**kwargs)
        self.fila = fila

    def raw_input(self, prompt=''):
        exibir_prompt(prompt)
        return self.fila.get()

Não conecte esse método diretamente à internet. Se o console remoto for realmente necessário, imponha autenticação forte, rede restrita, processo dedicado, usuário do sistema sem privilégios, limites de recursos e auditoria.

Capturar erros com write()

Por padrão, mensagens de sintaxe e tracebacks vão para sys.stderr. Sobrescreva write() para armazená-las ou enviá-las à interface.

class ConsoleCaptura(InteractiveConsole):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.erros = []

    def write(self, data):
        self.erros.append(data)

Evite devolver tracebacks completos para usuários externos, pois eles podem revelar caminhos, nomes de módulos e dados. Em interfaces administrativas internas, mantenha registros detalhados em canal protegido.

showsyntaxerror() e showtraceback()

showsyntaxerror() formata erros de compilação, enquanto showtraceback() lida com exceções de execução e remove o frame interno do interpretador. Desde o Python 3.5, exceções encadeadas são exibidas integralmente.

Você pode sobrescrever esses métodos para produzir JSON estruturado ou mensagens localizadas, mas preserve a exceção original em logs para diagnóstico.

Executar objetos de código com runcode()

runcode() recebe um objeto já compilado. Exceções comuns são capturadas e exibidas, mas SystemExit pode propagar. KeyboardInterrupt também pode surgir fora do ponto esperado.

codigo = compile('resultado = 6 * 7', '<console>', 'exec')
interp = InteractiveInterpreter()
interp.runcode(codigo)
print(interp.locals['resultado'])

O chamador deve definir uma política para encerramento e interrupção.

local_exit no Python 3.13+

InteractiveConsole e interact() aceitam local_exit=True. Nesse modo, chamadas a exit() e quit() encerram o console e retornam à aplicação, em vez de levantar SystemExit para todo o processo.

console = InteractiveConsole(local_exit=True)
console.interact()

Isso melhora a incorporação do REPL, mas não impede que código chame diretamente os._exit(), encerre threads ou altere o processo por outros meios.

Usar code.interact()

code.interact() é uma função de conveniência que cria um console temporário. Ela aceita banner, função de leitura, namespace, mensagem de saída e local_exit.

import code

estado = {'pedido_id': 123, 'modo': 'debug'}
code.interact(
    banner='Sessão de suporte local',
    local=estado,
    exitmsg='',
    local_exit=True,
)

É útil para abrir um console sob uma flag de desenvolvimento. Garanta que essa flag não fique habilitada em produção.

REPL para depuração

Um padrão é capturar o contexto de um ponto específico e iniciar uma sessão local.

def diagnosticar(objeto):
    code.interact(
        local={'objeto': objeto, 'resumo': objeto.resumo},
        local_exit=True,
    )

Não inclua tokens, senhas ou objetos com métodos destrutivos. Mesmo um console local pode ser exposto por logs de terminal compartilhados, gravação de sessão ou acesso indevido ao servidor.

Persistência do namespace

Variáveis, funções e classes permanecem no dicionário de locais enquanto a instância existir. Isso permite uma sessão natural, mas também pode reter grandes objetos e aumentar o consumo de memória.

Ofereça um comando para limpar o contexto ou recrie o console após determinado tempo. O guia sobre weakref no Python explica retenção de objetos, embora não substitua uma política explícita de ciclo de vida.

Pickle e objetos definidos no console

Funções e classes criadas pelo interpretador pertencem ao namespace fornecido. Elas só são serializáveis com pickle de forma convencional quando o namespace corresponde a um módulo importável existente. Não dependa de pickle para persistir uma sessão arbitrária.

Prefira salvar dados em formatos definidos e recriar funções a partir de código versionado. Nunca carregue pickle não confiável.

Isolamento real exige outro processo

Remover __builtins__ ou bloquear alguns nomes não cria sandbox. Python permite introspecção profunda, e objetos disponíveis podem abrir caminhos indiretos para funcionalidades perigosas.

Para reduzir impacto, execute o REPL em processo ou container descartável, com usuário sem privilégios, sistema de arquivos limitado, rede desabilitada, CPU e memória controladas e timeout. Mesmo assim, trate-o como execução de código, não como simples entrada de dados.

Testar um console customizado

Teste valores de retorno de push(), namespace, saída capturada, erros de sintaxe, exceções, comandos incompletos, EOF e encerramento local.

def teste_console():
    console = ConsoleCaptura(locals={})
    assert console.push('x = 10') is False
    assert console.locals['x'] == 10
    assert console.push('for i in range(2):') is True
    console.resetbuffer()

Use objetos falsos e não permita acesso real a produção durante testes.

Erros frequentes

  • Tratar um namespace reduzido como sandbox.
  • Expor o REPL em uma porta pública.
  • Deixar consoles de depuração ativos em produção.
  • Retornar tracebacks sensíveis ao cliente.
  • Ignorar SystemExit e KeyboardInterrupt.
  • Reter objetos grandes indefinidamente.
  • Tentar persistir funções de sessão com pickle.

Boas práticas

  • Use o módulo apenas para usuários confiáveis.
  • Prefira processos descartáveis para isolamento.
  • Controle namespace e ciclo de vida.
  • Capture saída por write().
  • Limite CPU, memória, rede e tempo.
  • Desative o recurso por padrão em produção.
  • Registre acesso e ações sem expor segredos.

Conclusão

O code no Python facilita a criação de REPLs personalizados com namespace persistente, buffering de blocos, prompts, tratamento de erros e encerramento local. Ele é uma base poderosa para ferramentas de desenvolvimento e diagnóstico.

Seu uso exige uma decisão de segurança explícita: o conteúdo é código executável. Para entradas não confiáveis, use isolamento de sistema operacional, não filtros no namespace. Consulte a documentação oficial do módulo code e a documentação do codeop.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código de aplicação web representando WSGI com wsgiref no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    wsgiref no Python: aplicações WSGI

    Aprenda wsgiref no Python para criar e validar aplicações WSGI, testar environ, headers, rotas e servidores locais sem usar em

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Protocolo seguro na internet representando preparação Unicode com stringprep no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    stringprep no Python: prepare Unicode

    Aprenda stringprep no Python para aplicar tabelas do RFC 3454, mapear Unicode, bloquear caracteres proibidos e validar regras bidirecionais.

    Ler mais

    Tempo de leitura: 7 minutos
    12/08/2026
    Rede de conexões representando I/O não bloqueante com selectors no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    selectors no Python: I/O não bloqueante

    Aprenda selectors no Python para monitorar vários sockets, eventos de leitura e escrita, timeouts e conexões não bloqueantes com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    11/08/2026
    Fluxo de dados em rede representando contexto assíncrono com contextvars no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextvars no Python: contexto assíncrono

    Aprenda contextvars no Python para armazenar estado por tarefa, evitar vazamentos em asyncio, copiar contextos e restaurar valores com tokens.

    Ler mais

    Tempo de leitura: 6 minutos
    11/08/2026
    Código de programação representando operações como funções com operator no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    operator no Python: operações como funções

    Aprenda operator no Python para usar operações como funções, ordenar campos, acessar itens, chamar métodos e trabalhar com pipelines funcionais.

    Ler mais

    Tempo de leitura: 5 minutos
    11/08/2026
    Alfabeto tridimensional representando normalização Unicode com unicodedata no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    unicodedata no Python: normalize Unicode

    Aprenda unicodedata no Python para normalizar Unicode, consultar nomes, categorias, números, caracteres combinantes e largura de exibição.

    Ler mais

    Tempo de leitura: 6 minutos
    11/08/2026