O módulo marshal lê e grava um formato binário interno usado principalmente pelo próprio Python para armazenar objetos de código em arquivos compilados. Ele consegue representar vários tipos básicos, como números, strings, bytes, tuplas, listas, sets, frozensets, dicionários e code objects, conforme a versão do interpretador.
Apesar de parecer uma alternativa rápida a JSON ou pickle, marshal não foi projetado como formato geral de persistência. A compatibilidade entre versões não é garantida para todos os tipos, o formato pode mudar e dados inválidos ou maliciosos não devem ser carregados. Seu uso ideal é restrito a ferramentas internas, experimentos controlados e compreensão da infraestrutura do Python.
marshal e arquivos .pyc
Quando um módulo Python é compilado, o interpretador cria um arquivo de bytecode em __pycache__. O conteúdo inclui um header gerenciado pela infraestrutura de import e uma representação do code object.
Não trate um arquivo .pyc inteiro como se fosse apenas o resultado de marshal.dumps(). O header contém metadados e pode mudar. Para ler bytecode, prefira ferramentas de import e módulos especializados.
Tipos básicos
O formato suporta um conjunto de tipos do próprio Python. Um exemplo simples:
import marshal
objeto = {
"nome": "exemplo",
"versao": 1,
"valores": [1, 2, 3],
}
dados = marshal.dumps(objeto)
restaurado = marshal.loads(dados)
print(restaurado)
O round trip preserva valores suportados, mas não transforma o formato em contrato público estável.
dump e load
dump(value, file) grava em um arquivo binário e load(file) lê um objeto.
import marshal
with open("estado.bin", "wb") as arquivo:
marshal.dump(objeto, arquivo)
with open("estado.bin", "rb") as arquivo:
objeto = marshal.load(arquivo)
Abra sempre em modo binário. Um stream de texto tenta converter bytes e falha.
dumps e loads
dumps() devolve bytes, enquanto loads() recebe um objeto bytes-like.
payload = marshal.dumps((1, 2, 3))
valor = marshal.loads(payload)
Use essa forma quando o armazenamento, hash ou transporte já trabalha com bytes.
Versão do formato
A função de gravação aceita uma versão do formato. O valor padrão corresponde ao formato atual recomendado pelo interpretador.
payload = marshal.dumps(objeto, 4)
Não escolha uma versão apenas por ser numericamente maior. Consulte a documentação do Python executado e teste leitura no ambiente de destino.
Compatibilidade não é garantia de API
O Python tenta manter determinados valores simples legíveis entre versões de formato, mas code objects não são compatíveis entre versões do interpretador. Detalhes internos podem mudar.
Se os dados precisam sobreviver a upgrades, ser compartilhados entre serviços ou lidos por outra linguagem, use um formato documentado e versionado.
Code objects
Um code object representa bytecode, constantes, nomes, variáveis e metadados de execução de uma função ou módulo.
import marshal
codigo = compile("resultado = 2 + 3", "exemplo.py", "exec")
payload = marshal.dumps(codigo)
restaurado = marshal.loads(payload)
namespace = {}
exec(restaurado, namespace)
print(namespace["resultado"])
Executar o objeto restaurado executa código. Faça isso somente com dados produzidos e protegidos pelo próprio sistema.
allow_code
Nas APIs atuais, o parâmetro allow_code permite controlar se code objects podem ser serializados ou desserializados.
dados = marshal.dumps(objeto, allow_code=False)
valor = marshal.loads(dados, allow_code=False)
Desabilitar code objects reduz uma categoria de risco, mas não transforma entrada hostil em segura.
Dados não confiáveis
A documentação alerta para não carregar dados recebidos de fonte não confiável. Um payload inválido pode provocar comportamento indefinido, falha, consumo excessivo ou outros problemas.
Não use marshal.loads() em request HTTP, mensagem de fila pública, upload de usuário ou cache compartilhado sem uma fronteira forte de confiança.
Assinatura e integridade
Quando o formato é usado internamente, proteja o arquivo com permissões e, quando necessário, assinatura ou MAC. Verificar integridade ajuda a detectar alteração.
A assinatura não resolve incompatibilidade de versão e só é confiável se a chave e o emissor estiverem protegidos.
Limite de tamanho
Antes de ler, verifique o tamanho do arquivo ou mensagem. Estruturas grandes podem consumir memória e CPU.
from pathlib import Path
caminho = Path("estado.bin")
if caminho.stat().st_size > 10_000_000:
raise ValueError("arquivo grande demais")
O limite deve refletir o caso real da aplicação.
Profundidade e recursão
Estruturas muito profundas podem exceder limites internos ou provocar erros. Não aumente limites de recursão apenas para aceitar payloads arbitrários.
Valide a estrutura lógica após a leitura e prefira dados rasos.
Tipos não suportados
Objetos de classes personalizadas, funções comuns, conexões, generators e muitos outros tipos não possuem representação marshal direta.
try:
marshal.dumps(object())
except ValueError as erro:
print(erro)
Não crie um sistema complexo de conversão apenas para forçar o uso do formato. JSON, dataclasses ou pickle controlado podem expressar melhor o domínio.
None e valores singleton
Valores como None, True e False são suportados. Após a carga, mantenha validações de tipo e schema.
O fato de o formato conseguir representar um valor não significa que ele seja válido para a aplicação.
Dicionários
Mappings serializados podem conter chaves e valores suportados. A ordem observável não deve ser usada como contrato do formato.
Para dados de configuração, prefira um schema explícito com nomes, tipos e versões.
Sets
Sets e frozensets podem ser suportados conforme o formato. Como não possuem ordem semântica, bytes gerados não devem ser usados como hash canônico de conteúdo.
Para assinatura determinística de dados, normalize a estrutura antes com uma especificação própria.
Floats e números complexos
O formato suporta tipos numéricos do Python, mas interoperabilidade com outra linguagem não é objetivo.
Se valores monetários ou decimais precisam de precisão e portabilidade, serialize strings ou inteiros segundo um schema explícito, em vez de depender de representação interna.
marshal versus pickle
Pickle suporta uma variedade maior de objetos e mecanismos de customização, como copyreg no Python. Ambos são formatos específicos do Python e não devem receber dados não confiáveis.
marshal é mais restrito e orientado ao interpretador, especialmente a code objects.
marshal versus JSON
JSON possui tipos mais limitados, mas é documentado, interoperável e adequado a APIs quando combinado com validação.
Use JSON para dados de negócio e comunicação. Use marshal apenas quando a ligação com internals do Python for uma exigência real.
marshal versus struct
struct empacota valores binários conforme um layout explícito. É melhor para protocolos e arquivos cujo formato precisa ser estável.
Marshal descreve objetos Python e não oferece um layout público apropriado para outras implementações.
Cache temporário
Um cache descartável criado e consumido pela mesma versão do Python pode ser um caso aceitável. O sistema deve conseguir apagar e reconstruir o cache quando a leitura falhar.
Nunca torne dados marshal a única cópia de informação importante.
Inclua metadados externos
Quando você controla um arquivo interno, guarde fora do payload a versão da aplicação, versão do Python, checksum e timestamp.
metadados = {
"python": platform.python_version(),
"schema": 1,
}
Esses dados ajudam a rejeitar caches incompatíveis antes da carga.
Escrita atômica
Grave primeiro em um arquivo temporário, faça flush quando necessário e substitua o destino com os.replace().
Uma interrupção durante escrita direta pode deixar um payload truncado que falhará depois.
Concorrência
Vários processos não devem sobrescrever o mesmo arquivo sem coordenação. Use locks, nomes por versão ou um sistema de cache apropriado.
Uma leitura simultânea durante substituição atômica normalmente vê a versão antiga ou nova, não um arquivo parcialmente escrito.
Erros de leitura
Capture erros esperados, descarte caches reconstruíveis e preserve diagnóstico.
try:
valor = marshal.loads(payload)
except (EOFError, ValueError, TypeError) as erro:
registrar_cache_invalido(erro)
valor = reconstruir()
Não continue com estado parcialmente lido.
Auditoria
Operações de marshal podem emitir eventos de auditoria do Python. Ambientes controlados podem monitorar carga de objetos e code objects.
Audit hooks complementam isolamento e permissões, não os substituem.
Análise de bytecode
Para estudar code objects, combine compile(), marshal em ambiente controlado e o módulo dis. Não execute bytecode desconhecido.
O artigo sobre ast no Python mostra uma camada estrutural anterior ao bytecode.
Testes entre versões
Se um cache atravessa deployments, execute uma matriz com as versões de Python suportadas. Teste leitura de arquivo antigo, rejeição de incompatível e reconstrução automática.
Não confie apenas no round trip dentro do mesmo processo.
Observabilidade
Registre tamanho, versão da aplicação, versão do Python, duração e motivo da invalidação. Não registre os bytes completos, que podem conter código ou dados sensíveis.
Erros comuns
Os erros mais frequentes são usar marshal como banco de dados, ler payload externo, presumir compatibilidade de code objects, tratar .pyc como payload puro, executar code object restaurado sem confiança, omitir limites e manter somente uma cópia importante no formato.
Conclusão
marshal é uma ferramenta interna do ecossistema Python, adequada a code objects e caches descartáveis sob controle estrito. Use arquivos binários, valide tamanho e versão, proteja origem e reconstrua o cache quando houver incompatibilidade.
Para dados de aplicação, prefira formatos estáveis e schemas explícitos. Consulte a documentação oficial de marshal e a documentação de dis.







