marshal no Python: serialização interna

Publicado em: 06/08/2026
Tempo de leitura: 7 minutos
Dados binários representando serialização interna com marshal no Python

O interpretador Python precisa gravar e carregar algumas estruturas internas com rapidez, especialmente objetos de código usados em arquivos .pyc. O módulo marshal no Python expõe esse formato binário de baixo nível para tipos simples e objetos internos. Ele pode ser útil em ferramentas especializadas, mas não foi projetado como formato geral de persistência, intercâmbio ou entrada externa.

Neste guia, você aprenderá a usar dump(), load(), dumps() e loads(), controlar versões e bloquear code objects. O conteúdo complementa nossos artigos sobre pickle, pickletools, py_compile, bytecode com dis e comparação de arquivos.

Para que marshal existe

Marshal foi criado para necessidades internas do Python. Seu principal uso é apoiar a leitura e escrita de estruturas do interpretador, não fornecer um protocolo estável para aplicações.

Ao contrário de JSON, ele não prioriza interoperabilidade. Ao contrário de pickle, não tenta serializar instâncias arbitrárias de classes. A documentação deixa claro que detalhes do formato podem mudar entre versões.

Serializar em memória

marshal.dumps() converte um valor suportado em bytes.

import marshal

objeto = {
    "nome": "Ana",
    "pontos": [10, 20, 30],
}

dados = marshal.dumps(objeto)
print(type(dados), len(dados))

O resultado é binário e não deve ser editado manualmente.

Restaurar a partir de bytes

marshal.loads() lê um valor dos bytes.

restaurado = marshal.loads(dados)
print(restaurado)

Use somente bytes produzidos por um ambiente confiável e compatível. A documentação oficial de marshal adverte explicitamente contra dados não confiáveis.

Gravar em arquivo

dump() escreve um valor em um objeto de arquivo binário.

with open("dados.marshal", "wb") as arquivo:
    marshal.dump(objeto, arquivo)

Se o valor contém um tipo não suportado, a função gera ValueError. Parte de dados inválidos pode já ter sido escrita no arquivo, portanto não reutilize o destino depois de uma falha.

Gravação atômica

Para evitar arquivos parciais, grave em um temporário e substitua o destino somente após sucesso.

from pathlib import Path

caminho = Path("dados.marshal")
temporario = caminho.with_suffix(".tmp")

with temporario.open("wb") as arquivo:
    marshal.dump(objeto, arquivo)

temporario.replace(caminho)

Essa técnica reduz corrupção por erro de serialização, mas não garante durabilidade contra perda de energia sem flush e sincronização adequados.

Ler de um arquivo

load() lê um único valor a partir da posição atual.

with open("dados.marshal", "rb") as arquivo:
    objeto = marshal.load(arquivo)

Bytes posteriores ao primeiro valor permanecem no arquivo. Isso permite concatenar vários valores, mas a aplicação precisa saber quantos existem ou usar framing próprio.

Vários valores em sequência

with open("sequencia.marshal", "wb") as arquivo:
    marshal.dump({"id": 1}, arquivo)
    marshal.dump({"id": 2}, arquivo)

with open("sequencia.marshal", "rb") as arquivo:
    primeiro = marshal.load(arquivo)
    segundo = marshal.load(arquivo)

Sem contador, tamanho ou marcador externo, não existe uma forma robusta de distinguir final válido de truncamento apenas pelo protocolo da aplicação.

Tipos suportados

Marshal trabalha com vários tipos simples usados internamente, incluindo:

  • None, booleanos e números;
  • strings e objetos de bytes;
  • tuplas, listas e dicionários;
  • sets e frozensets;
  • algumas estruturas adicionais conforme a versão do formato;
  • objetos de código quando permitidos.

Instâncias arbitrárias de classes não são suportadas como no pickle.

Recursão em contêineres

Versões modernas do formato conseguem representar determinados contêineres recursivos.

lista = []
lista.append(lista)

dados = marshal.dumps(lista)
restaurada = marshal.loads(dados)
assert restaurada[0] is restaurada

Estruturas extremamente profundas podem atingir limites e causar falhas. Não use profundidade sem controle.

Versão do formato

O módulo expõe marshal.version, que indica a versão atual do formato usada por padrão.

print(marshal.version)

dados = marshal.dumps(objeto, marshal.version)

O parâmetro de versão controla o formato, não a compatibilidade completa entre interpretadores. Um valor suportado hoje pode envolver tipos que outra versão não entende.

Não confundir formato com versão do Python

O número do formato marshal não é igual ao número de versão do Python. Além disso, objetos de código podem mudar mesmo quando o formato marshal é reconhecido.

Registre implementação, versão completa do Python, plataforma e versão do formato junto ao artefato quando a compatibilidade importa.

Objetos de código

Code objects representam bytecode, constantes, nomes e metadados de uma função ou módulo compilado.

codigo = compile("resultado = 2 + 2", "<exemplo>", "exec")
dados = marshal.dumps(codigo)
restaurado = marshal.loads(dados)

Executar o objeto restaurado continua sendo execução de código.

ambiente = {}
exec(restaurado, ambiente)
print(ambiente["resultado"])

Nunca execute code objects vindos de uma origem desconhecida.

Bloquear code objects

Versões recentes oferecem o argumento nomeado allow_code.

dados = marshal.dumps(
    objeto,
    allow_code=False,
)

restaurado = marshal.loads(
    dados,
    allow_code=False,
)

Quando falso, serializar ou carregar objetos de código é rejeitado. Esse controle reduz uma categoria de dados, mas não transforma bytes hostis em entrada segura.

Compatibilidade de code objects

A documentação alerta que o formato dos objetos de código não é compatível entre versões do Python. Carregar um code object de versão incorreta possui comportamento indefinido.

Não armazene code objects como cache duradouro. Use o mecanismo oficial de .pyc, que inclui tags e cabeçalhos de validação.

marshal e arquivos pyc

Embora arquivos .pyc usem marshal para a parte do code object, eles também possuem cabeçalho gerenciado por importlib. Não tente construir um pyc apenas gravando marshal.dumps(codigo).

Use py_compile ou compileall para gerar caches válidos.

marshal versus pickle

Pickle suporta classes personalizadas e protocolos de reconstrução, mas pode executar callables durante a carga. Marshal suporta um conjunto menor e continua sendo inseguro para dados não confiáveis.

Nenhum dos dois é adequado para uploads externos. Para dados, prefira JSON, banco de dados ou um formato com esquema.

marshal versus JSON

JSON possui interoperabilidade, texto legível e um modelo restrito. Marshal é específico do Python e otimizado para detalhes internos.

Mesmo quando marshal produz arquivos menores, a falta de estabilidade costuma ser um custo maior em persistência de aplicação.

Detecção de truncamento

Um arquivo incompleto pode gerar EOFError, ValueError ou outro erro de leitura.

try:
    with open("dados.marshal", "rb") as arquivo:
        objeto = marshal.load(arquivo)
except (EOFError, ValueError, TypeError) as erro:
    print("Arquivo inválido:", erro)

Não tente continuar usando um valor parcialmente lido.

Integridade externa

Quando dados internos precisam ser armazenados, mantenha hash ou HMAC separado.

import hashlib

assinatura = hashlib.sha256(dados).hexdigest()

Um hash simples detecta corrupção acidental, mas não adulteração por um invasor que pode recalculá-lo. Para autenticidade, use HMAC com uma chave secreta.

Limites de recursos

Dados malformados podem tentar criar estruturas grandes ou profundas. Antes de ler, limite o tamanho do arquivo e processe entradas potencialmente hostis em subprocesso com memória e tempo controlados.

from pathlib import Path

caminho = Path("dados.marshal")
if caminho.stat().st_size > 10_000_000:
    raise ValueError("arquivo grande demais")

Essa verificação não substitui isolamento.

Eventos de auditoria

Operações de marshal geram eventos de auditoria do Python. Ambientes embutidos e políticas de segurança podem observar carregamentos e gravações.

Não dependa apenas desses eventos para impedir entrada perigosa. A validação de origem deve acontecer antes da chamada.

Uso em testes e ferramentas

Marshal pode ser útil em testes do próprio interpretador, estudos de formato e ferramentas que trabalham com artefatos efêmeros da mesma versão.

Documente explicitamente que o arquivo é descartável e deve ser regenerado ao trocar de runtime.

Teste de round-trip

def test_round_trip():
    original = {
        "ids": [1, 2, 3],
        "ativo": True,
    }
    restaurado = marshal.loads(marshal.dumps(original))
    assert restaurado == original

Teste tipos suportados, arquivo vazio, truncamento, versão escolhida e allow_code=False.

Erros frequentes

  • Usar marshal como banco de dados duradouro.
  • Carregar bytes recebidos de usuários.
  • Presumir compatibilidade entre versões.
  • Executar code objects restaurados.
  • Ignorar arquivo parcial após ValueError.
  • Confundir dados marshal com pyc completo.
  • Não limitar tamanho e profundidade.
  • Tratar allow_code=False como sandbox.

Boas práticas

  • Use marshal somente para necessidades internas e efêmeras.
  • Mantenha versão de Python e formato registradas.
  • Bloqueie code objects quando não forem necessários.
  • Grave por arquivo temporário e substituição.
  • Valide tamanho antes de carregar.
  • Use integridade autenticada para dados internos.
  • Regere artefatos ao trocar de runtime.
  • Prefira formatos estáveis para dados de aplicação.

Conclusão

O módulo marshal no Python oferece serialização binária rápida para um conjunto de tipos e estruturas internas do interpretador. Ele explica parte do funcionamento dos caches de bytecode e pode apoiar ferramentas especializadas.

Seu contrato é deliberadamente limitado: o formato não é estável para persistência geral, code objects não são portáveis e dados desconhecidos não são seguros. Use marshal apenas em ambientes controlados, com artefatos descartáveis, limites de recursos e compatibilidade de runtime bem definida.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Monitor com código binário representando personalização de pickle com copyreg no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    copyreg no Python: personalize o pickle

    Aprenda copyreg no Python para registrar funções de redução, personalizar pickle e preservar compatibilidade de objetos.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    functools.partial no Python: guia prático

    Aprenda functools.partial no Python para fixar argumentos, adaptar callbacks e criar funções especializadas com clareza.

    Ler mais

    Tempo de leitura: 6 minutos
    06/08/2026
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    filecmp no Python: compare arquivos e pastas

    Aprenda filecmp no Python para comparar arquivos e pastas, usar shallow, dircmp, cmpfiles, cache e hashes de integridade.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Terminal de comandos representando parsing seguro com shlex no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shlex no Python: comandos e argumentos seguros

    Aprenda shlex no Python para separar comandos, tratar aspas, usar quote e join e reduzir riscos de injeção ao executar

    Ler mais

    Tempo de leitura: 7 minutos
    02/08/2026
    Banco de dados local representando persistência com shelve no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    shelve no Python: persistência simples

    Aprenda shelve no Python para persistir objetos, atualizar dados mutáveis, evitar riscos de pickle e saber quando migrar para SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    01/08/2026
    Documentos de texto representando comparação de versões com difflib no Python
    Bibliotecas e Módulos
    Foto de perfil de Leandro Hirt da Academify

    difflib no Python: compare textos e arquivos

    Aprenda difflib no Python para comparar textos, medir similaridade, criar diffs unificados, relatórios HTML e sugestões de nomes.

    Ler mais

    Tempo de leitura: 7 minutos
    01/08/2026