copyreg no Python: personalize o pickle

Publicado em: 27/08/2026
Tempo de leitura: 8 minutos
A close-up view of fresh, green cucumbers ready for pickling and preservation in Estonia.

O módulo copyreg permite registrar funções usadas pelo mecanismo de serialização pickle para tipos que não controlam diretamente sua própria redução. Ele é especialmente útil para extensões nativas, classes de terceiros, wrappers e objetos cuja forma serializada precisa ser definida fora da classe.

Na maioria das classes próprias, métodos como __reduce__(), __reduce_ex__(), __getstate__() e __setstate__() são mais fáceis de localizar e manter. copyreg deve ser usado quando o registro externo é realmente desejável. Também é importante lembrar que pickle não é seguro para dados não confiáveis: carregar um payload pode executar código.

Como pickle reconstrói um objeto

O pickle não grava uma cópia bruta da memória. Ele descreve como reconstruir o objeto: uma função ou callable, argumentos, estado adicional, itens de sequência e pares de mapping.

Uma função de redução simples retorna um callable e uma tupla de argumentos.

class Ponto:
    def __init__(self, x, y):
        self.x = x
        self.y = y


def reconstruir_ponto(x, y):
    return Ponto(x, y)


def reduzir_ponto(obj):
    return reconstruir_ponto, (obj.x, obj.y)

copyreg.pickle() associa essa função ao tipo.

Registre um tipo

import copyreg
import pickle

copyreg.pickle(Ponto, reduzir_ponto)

dados = pickle.dumps(Ponto(2, 5))
restaurado = pickle.loads(dados)
print(restaurado.x, restaurado.y)

O registro é global ao processo e afeta serializações posteriores daquele tipo. Faça-o durante a inicialização, em um local previsível.

O construtor precisa ser importável

Funções usadas para reconstrução devem ser importáveis pelo nome de módulo quando o pickle for carregado em outro processo. Funções locais, lambdas e closures geralmente não funcionam.

Defina o reconstrutor no nível do módulo e mantenha seu caminho estável. Renomear ou mover a função pode quebrar dados antigos.

Função de redução no nível do módulo

A função registrada também deve permanecer disponível enquanto a aplicação serializa. Evite criar registros dentro de requests ou funções temporárias.

def registrar_serializacao():
    copyreg.pickle(Ponto, reduzir_ponto)

Chame uma vez na inicialização do pacote ou do processo.

Estado adicional

A tupla de redução pode conter um terceiro item com estado adicional. Depois de criar a instância, pickle aplica o estado usando __setstate__() ou atualizando __dict__ quando apropriado.

def reduzir_documento(obj):
    estado = {"titulo": obj.titulo, "tags": obj.tags}
    return Documento, (), estado

O construtor chamado durante a reconstrução deve aceitar os argumentos fornecidos.

Objetos com __slots__

Classes com slots podem precisar de um estado explícito porque não possuem um __dict__ tradicional.

def reduzir_usuario(obj):
    return criar_usuario, (obj.id, obj.nome)

Evite depender de detalhes internos do layout. Defina uma representação lógica e estável.

Tipos de extensões nativas

copyreg é comum quando um tipo vem de C ou de uma biblioteca externa e não pode ser alterado. Uma função Python pode extrair os valores necessários e escolher um reconstrutor.

Confirme que handles, ponteiros, conexões e recursos do sistema não são serializados como se fossem portáveis. Normalmente apenas identificadores ou dados devem ser preservados.

Não serialize recursos ativos

Sockets, arquivos abertos, locks, threads, processos e conexões de banco não podem ser reconstruídos com segurança a partir do estado bruto.

Serialização deve guardar configuração ou identificadores. O processo restaurado abre um novo recurso e trata falhas de conexão.

Compatibilidade entre versões

Pickles podem permanecer armazenados por anos. Uma alteração no callable, argumentos ou estado pode quebrar a leitura.

Inclua uma versão no estado e mantenha caminhos de migração.

estado = {
    "versao": 2,
    "nome": obj.nome,
    "opcoes": obj.opcoes,
}

O reconstrutor ou __setstate__() pode aceitar versões anteriores.

Protocolos do pickle

O protocolo escolhido influencia eficiência e recursos. A função de redução registrada por copyreg não recebe automaticamente o número do protocolo.

Quando o comportamento precisa variar por protocolo, implementar __reduce_ex__(protocol) na classe pode ser mais adequado.

copyreg e classes próprias

Para uma classe que você controla, manter a lógica dentro dela geralmente melhora a descoberta.

class Ponto:
    def __reduce__(self):
        return type(self), (self.x, self.y)

Use registro externo para separar políticas, integrar tipos externos ou evitar modificar uma API pública.

dispatch_table personalizado

Picklers personalizados podem possuir uma dispatch_table própria, permitindo regras locais sem alterar o registro global.

import copyreg
import io
import pickle

buffer = io.BytesIO()
pickler = pickle.Pickler(buffer)
pickler.dispatch_table = copyreg.dispatch_table.copy()
pickler.dispatch_table[Ponto] = reduzir_ponto
pickler.dump(Ponto(1, 2))

Essa abordagem é melhor quando bibliotecas diferentes precisam de políticas distintas.

Evite conflito global

Dois pacotes podem tentar registrar redutores diferentes para o mesmo tipo. O último registro pode alterar o comportamento de toda a aplicação.

Prefira dispatch tables locais em bibliotecas reutilizáveis. Se o registro global for inevitável, documente-o e faça testes de integração.

constructor

A função copyreg.constructor() marca um callable como construtor seguro para determinados mecanismos históricos. Em código moderno, seu uso direto é raro.

Não interprete o nome “constructor” como garantia de segurança contra payload malicioso. A desserialização continua capaz de executar callables.

Códigos de extensão

add_extension(), remove_extension() e clear_extension_cache() gerenciam códigos compactos para referências globais em pickles.

import copyreg

copyreg.add_extension("meupacote.modelos", "Ponto", 1001)

Esses códigos fazem parte de um registro global e precisam ser coordenados. Colisões podem causar erros ou reconstrução incorreta.

Faixa e governança dos códigos

Não escolha números aleatórios em bibliotecas distribuídas sem uma política. O mesmo código deve identificar sempre o mesmo módulo e nome.

Remover ou reutilizar um código pode tornar pickles antigos perigosamente ambíguos.

Cache de extensões

O unpickler pode manter um cache para resolver códigos de extensão. clear_extension_cache() limpa esse estado, principalmente em testes ou cenários muito específicos.

Não limpe o cache continuamente em produção; isso pode prejudicar desempenho sem resolver problemas de compatibilidade.

Segurança do pickle

Nunca chame pickle.loads() com dados recebidos de usuário, rede, arquivo não confiável ou bucket compartilhado. O formato permite indicar funções a serem chamadas durante a reconstrução.

Assinatura criptográfica verifica origem e integridade, mas só é segura quando as chaves e o emissor são confiáveis. Para dados interoperáveis, prefira JSON, MessagePack ou outro formato sem execução automática.

Validação depois da carga

Mesmo um pickle confiável pode estar antigo ou corrompido. Valide tipos, limites, versões e invariantes após carregar.

Não presuma que a função registrada sempre recebe argumentos razoáveis. Um payload manipulado dentro de um ambiente confiável também pode causar consumo excessivo.

Limites de tamanho

Pickle pode representar estruturas enormes e profundamente aninhadas. Limite o tamanho do arquivo antes da carga e execute processamentos de risco em ambiente com memória e CPU controladas.

Não há um parâmetro universal de profundidade segura no loads().

Multiprocessing

Process pools usam serialização para enviar tarefas e resultados. Um registro de copyreg pode permitir que um tipo seja transferido, mas o worker também precisa importar o código de registro.

Faça a configuração em um módulo importável e teste com o método de início spawn. Veja multiprocessing no Python.

Objetos grandes

Personalizar a redução pode diminuir o payload ao guardar somente estado essencial. Meça tamanho e tempo antes e depois.

Não sacrifique compatibilidade e clareza por uma micro-otimização. Dados redundantes às vezes tornam migrações mais simples.

Herança

Um registro para uma classe não deve ser presumido como regra automática adequada para todas as subclasses. Subclasses podem adicionar estado ou invariantes.

Teste o tipo exato e decida se cada subclasse precisa de redutor próprio.

Dataclasses e named tuples

Muitos tipos Python comuns já são serializáveis sem configuração extra. Não registre uma função apenas porque o tipo possui vários campos.

Use copyreg quando a serialização padrão é incorreta, instável ou impossível.

Testes de round trip

Um teste básico serializa, desserializa e compara estado e comportamento.

original = Ponto(2, 5)
restaurado = pickle.loads(pickle.dumps(original))
assert (restaurado.x, restaurado.y) == (2, 5)

Inclua protocolos diferentes, processos separados, versões antigas e dados inválidos.

Teste em processo novo

Um round trip no mesmo processo pode esconder dependências do registro e imports já carregados. Execute a leitura em um subprocesso limpo ou em testes de integração.

Isso revela funções locais, caminhos de módulo errados e inicialização ausente.

Observabilidade

Registre tipo, versão do estado, protocolo, tamanho e duração sem armazenar o payload completo. Pickles podem conter segredos.

Falhas de reconstrução devem incluir o identificador do objeto ou job, não os bytes serializados.

Erros comuns

Os erros mais frequentes são registrar lambdas, mover o reconstrutor sem migração, serializar handles ativos, carregar dados não confiáveis, alterar o registro global em uma biblioteca, ignorar subclasses, reutilizar código de extensão e testar apenas no mesmo processo.

Conclusão

copyreg permite ensinar ao pickle como reduzir e reconstruir tipos que não controlam sua própria serialização. Use funções de módulo estáveis, estado versionado, dispatch tables locais quando possível e testes em processos limpos.

Não use pickle como formato para entrada não confiável. Consulte a documentação oficial de copyreg e a documentação de pickle.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    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
    A close-up shot showcasing the intricate scales of a snake, highlighting texture and color.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    graphlib no Python: ordenação topológica

    Aprenda graphlib no Python para ordenar dependências, detectar ciclos, executar tarefas prontas em paralelo e criar pipelines seguros.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    weakref: evite reter objetos em caches

    Aprenda weakref no Python para referências fracas, caches, WeakSet, WeakMethod, finalize, callbacks e prevenção de retenção acidental.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Young professional woman working on a laptop in an office setting, concentrating on her task.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextlib no Python: gerencie recursos

    Aprenda contextlib no Python com contextmanager, ExitStack, suppress, closing, asynccontextmanager e cleanup seguro de recursos.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    Vivid close-up of code on a computer screen showcasing programming details.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ast no Python: analise código-fonte

    Aprenda ast no Python para analisar e transformar código, criar visitors, preservar posições, usar literal_eval e evitar riscos de execução.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    Rustic exposed brick wall featuring aged electrical sockets and metal conduit.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    socket no Python: redes TCP e UDP

    Aprenda socket no Python para clientes e servidores TCP, UDP, framing, timeouts, IPv6, concorrência, TLS e segurança de rede.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026