# `pickle` — Serialização de objetos Python

Código-fonte: Lib/pickle.py

O módulo `pickle` implementa protocolos binários para serializar e desserializar uma estrutura de objeto Python. “Pickling” é o processo pelo qual uma hierarquia de objetos Python é convertida em um fluxo de bytes, e “unpickling” é a operação inversa, em que um fluxo de bytes (de um arquivo binário ou objeto bytes ou similar) é convertido de volta em uma hierarquia de objetos. Pickling (e unpickling) com pickle é alternativamente conhecido como “serialização”, “marshalling” [1] ou “flattening”; no entanto, para evitar confusão, usa-se is termos “pickling” e “unpickling”. Nesta documentação traduzida, usaremos “serialização com pickle” e “desserialização com pickle”, respectivamente.

Aviso

O módulo `pickle` não é seguro. Desserialize com pickle apenas os dados em que você confia.

É possível construir dados maliciosos em pickle que irão executar código arbitrário durante o processo de desserialização com pickle. Nunca desserialize com pickle os dados que possam vir de uma fonte não confiável ou que possam ter sido adulterados.

Considere assinar dados com `hmac` se você precisar garantir que eles não foram adulterados.

Formatos de serialização mais seguros como `json` podem ser mais apropriados se você estiver processando dados não confiáveis. Vejo Comparação com json.

## Relacionamento com outros módulos Python

### Comparação com `marshal`

Python tem um módulo de serialização mais primitivo chamado `marshal`, mas em geral `pickle` deve ser sempre a forma preferida de serializar objetos Python. `marshal` existe principalmente para oferecer suporte a arquivos `.pyc` do Python.

O módulo `pickle` difere do `marshal` de várias maneiras significativas:

- `marshal` não pode ser usado para serializar classes definidas pelo usuário e suas instâncias. `pickle` pode salvar e restaurar instâncias de classe de forma transparente, no entanto, a definição de classe deve ser importável e viver no mesmo módulo de quando o objeto foi armazenado.

- O formato de serialização do `marshal` não tem garantia de portabilidade entre as versões do Python. Como sua principal tarefa em vida é oferecer suporte a arquivos `.pyc`, os implementadores do Python se reservam o direito de alterar o formato de serialização de maneiras não compatíveis com versões anteriores, caso haja necessidade. O formato de serialização do `pickle` tem a garantia de ser compatível com versões anteriores em todas as versões do Python, desde que um protocolo pickle compatível seja escolhido e o código de serialização e desserialização com pickle lide com diferenças de tipo Python 2 a Python 3 se seus dados estiverem cruzando aquele limite de mudança de linguagem exclusivo.

### Comparação com `json`

Existem diferenças fundamentais entre os protocolos pickle e JSON (JavaScript Object Notation):

- JSON é um formato de serialização de texto (ele produz texto unicode, embora na maioria das vezes seja codificado para `utf-8`), enquanto pickle é um formato de serialização binário;

- JSON é legível por humanos, enquanto pickle não é;

- JSON é interoperável e amplamente usado fora do ecossistema Python, enquanto pickle é específico para Python;

- JSON, por padrão, só pode representar um subconjunto dos tipos embutidos do Python, e nenhuma classe personalizada; pickle pode representar um número extremamente grande de tipos Python (muitos deles automaticamente, pelo uso inteligente dos recursos de introspecção do Python; casos complexos podem ser resolvidos implementando APIs de objetos específicos);

- Ao contrário do pickle, a desserialização não confiável do JSON não cria, por si só, uma vulnerabilidade de execução de código arbitrário.

Ver também

O módulo `json`: um módulo de biblioteca padrão que permite a serialização e desserialização JSON.

## Formato de fluxo de dados

O formato de dados usado pelo `pickle` é específico do Python. Isso tem a vantagem de não haver restrições impostas por padrões externos, como JSON (que não pode representar o compartilhamento de ponteiros); no entanto, isso significa que programas não Python podem não ser capazes de reconstruir objetos Python serializados com pickle.

Por padrão, o formato de dados do `pickle` usa uma representação binária relativamente compacta. Se você precisa de características de tamanho ideal, pode com eficiência comprimir dados processados com pickle.

O módulo `pickletools` contém ferramentas para analisar fluxos de dados gerados por `pickle`. O código-fonte do `pickletools` tem extensos comentários sobre códigos de operações usados por protocolos de pickle.

Existem atualmente 6 protocolos diferentes que podem ser usados para a serialização com pickle. Quanto mais alto o protocolo usado, mais recente é a versão do Python necessária para ler o pickle produzido.

- A versão 0 do protocolo é o protocolo original “legível por humanos” e é compatível com versões anteriores do Python.

- A versão 1 do protocolo é um formato binário antigo que também é compatível com versões anteriores do Python.

- A versão 2 do protocolo foi introduzida no Python 2.3. Ela fornece uma serialização com pickle muito mais eficiente de classes estilo novo. Consulte PEP 307 para obter informações sobre as melhorias trazidas pelo protocolo 2.

- A versão 3 do protocolo foi adicionada ao Python 3.0. Ela tem suporte explícito a objetos `bytes` e não é possível desserializar com pickle a partir do Python 2.x. Este era o protocolo padrão no Python 3.0–3.7.

- A versão 4 do protocolo foi adicionada ao Python 3.4. Ela adiciona suporte para objetos muito grandes, serialização com pickle de mais tipos de objetos e algumas otimizações de formato de dados. É o protocolo padrão a partir do Python 3.8. Consulte PEP 3154 para obter informações sobre as melhorias trazidas pelo protocolo 4.

- A versão 5 do protocolo foi adicionada ao Python 3.8. Ela adiciona suporte a dados fora da banda e aumento de velocidade para dados dentro da banda. Consulte PEP 574 para obter informações sobre as melhorias trazidas pelo protocolo 5.

Nota

A serialização é uma noção mais primitiva do que a persistência; embora o `pickle` leia e escreva objetos arquivo, ele não lida com a questão de nomear objetos persistentes, nem a questão (ainda mais complicada) de acesso simultâneo a objetos persistentes. O módulo `pickle` pode transformar um objeto complexo em um fluxo de bytes e pode transformar o fluxo de bytes em um objeto com a mesma estrutura interna. Talvez a coisa mais óbvia a fazer com esses fluxos de bytes seja escrevê-los em um arquivo, mas também é concebível enviá-los através de uma rede ou armazená-los em um banco de dados. O módulo `shelve` fornece uma interface simples para serializar e desserializar com pickle os objetos em arquivos de banco de dados no estilo DBM.

## Interface do módulo

Para serializar uma hierarquia de objeto, você simplesmente chama a função `dumps()`. Da mesma forma, para desserializar um fluxo de dados, você chama a função `loads()`. No entanto, se você quiser mais controle sobre a serialização e desserialização, pode criar um objeto `Pickler` ou `Unpickler`, respectivamente.

O módulo `pickle` fornece as seguintes constantes:

pickle.HIGHEST_PROTOCOL

  Um inteiro, a mais alta versão de protocolo disponível. Este valor pode ser passado como um valor de protocol para as funções `dump()` e `dumps()`, bem como o construtor de `Pickler`.

pickle.DEFAULT_PROTOCOL

  Um inteiro, a versão de protocolo padrão usada para a serialização com pickle. Pode ser menor que `HIGHEST_PROTOCOL`. Atualmente, o protocolo padrão é 4, introduzido pela primeira vez no Python 3.4 e incompatível com as versões anteriores.

  Alterado na versão 3.0: O protocolo padrão é 3.

  Alterado na versão 3.8: O protocolo padrão é 4.

O módulo `pickle` fornece as seguintes funções para tornar o processo de serialização com pickle mais conveniente:

pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)

  Escreve a representação após a serialização com pickle do objeto obj no objeto arquivo aberto file. Isso é equivalente a `Pickler(file, protocol).dump(obj)`.

  Os argumentos file, protocol, fix_imports e buffer_callback têm o mesmo sentido que no construtor de `Pickler`.

  Alterado na versão 3.8: O argumento buffer_callback foi adicionado.

pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)

  Retorna a representação em após a serialização com pickle do objeto obj como um objeto `bytes`, ao invés de escrevê-lo em um arquivo.

  Os argumentos protocol, fix_imports e buffer_callback têm o mesmo sentido que no construtor de `Pickler`.

  Alterado na versão 3.8: O argumento buffer_callback foi adicionado.

pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

  Lê a representação serializada com pickle de um objeto a partir de objeto arquivo aberto file e retorna a hierarquia de objeto reconstituído especificada nele. Isso é equivalente a `Unpickler(file).load()`.

  A versão do protocolo pickle é detectada automaticamente, portanto, nenhum argumento de protocolo é necessário. Bytes após a representação serializada com pickle do objeto são ignorados.

  Os argumentos file, fix_imports, encoding, errors, strict e buffers têm o mesmo significado que no construtor construtor `Unpickler`.

  Alterado na versão 3.8: O argumento buffers foi adicionado.

pickle.loads(data, /, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

  Retorna a hierarquia de objeto reconstituído da representação serializada com pickle data de um objeto. data deve ser um objeto bytes ou similar.

  A versão do protocolo pickle é detectada automaticamente, portanto, nenhum argumento de protocolo é necessário. Bytes após a representação serializada com pickle do objeto são ignorados.

  Os argumentos fix_imports, encoding, errors, strict e buffers têm o mesmo significado que no construtor construtor `Unpickler`.

  Alterado na versão 3.8: O argumento buffers foi adicionado.

O módulo `pickle` define três exceções:

exception pickle.PickleError

  Classe base comum para as outras exceções de serialização com pickle. Herda de `Exception`.

exception pickle.PicklingError

  Erro levantado quando um objeto não serializável com pickle é encontrado por `Pickler`. Herda de `PickleError`.

  Consulte O que pode ser serializado e desserializado com pickle? para saber quais tipos de objetos podem ser serializados com pickle.

exception pickle.UnpicklingError

  Erro levantado quando há um problema ao desserializar com pickle um objeto, como dados corrompidos ou violação de segurança. Herda de `PickleError`.

  Observe que outras exceções também podem ser levantadas durante a desserialização com pickle, incluindo (mas não necessariamente limitado a) AttributeError, EOFError, ImportError e IndexError.

O módulo `pickle` exporta três classes, `Pickler`, `Unpickler` e `PickleBuffer`:

class pickle.Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)

  Isso leva um arquivo binário a escrever um fluxo de dados pickle.

  O argumento opcional protocol, um inteiro, diz ao pickler para usar o protocolo fornecido; os protocolos suportados são de 0 a `HIGHEST_PROTOCOL`. Se não for especificado, o padrão é `DEFAULT_PROTOCOL`. Se um número negativo for especificado, `HIGHEST_PROTOCOL` é selecionado.

  O argumento file deve ter um método write() que aceite um argumento de um único byte. Portanto, pode ser um arquivo em disco aberto para escrita binária, uma instância `io.BytesIO` ou qualquer outro objeto personalizado que atenda a esta interface.

  Se fix_imports for verdadeiro e protocolo for menor que 3, pickle tentará mapear os novos nomes do Python 3 para os nomes dos módulos antigos usados no Python 2, de modo que o fluxo de dados pickle seja legível com o Python 2.

  Se buffer_callback for `None` (o padrão), as visualizações de buffer são serializadas em file como parte do fluxo pickle.

  Se buffer_callback não for `None`, ele pode ser chamado qualquer número de vezes com uma visualização de buffer. Se essa chamada retornar um valor falso (tal como `None`), o buffer fornecido é fora da banda; caso contrário, o buffer é serializado dentro da banda, ou seja, dentro do fluxo pickle.

  É um erro se buffer_callback não for `None` e protocol for `None` ou menor que 5.

  Alterado na versão 3.8: O argumento buffer_callback foi adicionado.

  dump(obj)

    Escreve a representação serializada em pickle de obj no objeto arquivo aberto fornecido no construtor.

  persistent_id(obj)

    Não faz nada por padrão. Isso existe para que uma subclasse possa substituí-lo.

    Se `persistent_id()` retornar `None`, obj é serializado com pickle como de costume. Qualquer outro valor faz com que `Pickler` emita o valor retornado como um ID persistente para obj. O significado deste ID persistente deve ser definido por `Unpickler.persistent_load()`. Observe que o valor retornado por `persistent_id()` não pode ter um ID persistente.

    Consulte Persistência de objetos externos para detalhes e exemplos de usos.

    Alterado na versão 3.13: Foi adicionada a implementação padrão desse método na implementação em C da `Pickler`.

  dispatch_table

    A tabela de despacho de um objeto pickler é um registro de funções de redução do tipo que pode ser declarado usando `copyreg.pickle()`. É um mapeamento cujas chaves são classes e cujos valores são funções de redução. Uma função de redução leva um único argumento da classe associada e deve estar de acordo com a mesma interface de um método `__reduce__()`.

    Por padrão, um objeto pickler não terá um atributo `dispatch_table`, e em vez disso usará a tabela de despacho global gerenciada pelo módulo `copyreg`. No entanto, para personalizar a serialização com pickle de um objeto pickler específico, pode-se definir o atributo `dispatch_table` para um objeto do tipo dict. Alternativamente, se uma subclasse de `Pickler` tem um atributo `dispatch_table` então ele será usado como a tabela de despacho padrão para instâncias daquela classe.

    Consulte Tabelas de despacho para exemplos de uso.

    Adicionado na versão 3.3.

  reducer_override(obj)

    Redutor especial que pode ser definido em subclasses de `Pickler`. Este método tem prioridade sobre qualquer redutor em `dispatch_table`. Ele deve estar de acordo com a mesma interface que um método `__reduce__()` e pode opcionalmente retornar `NotImplemented` como alternativa em redutores registrados em `dispatch_table` para serializar com pickle `obj`.

    Para exemplo detalhado, consulte Redução personalizada para tipos, funções e outros objetos.

    Adicionado na versão 3.8.

  fast

    Descontinuado. Ative o modo rápido se definido como um valor verdadeiro. O modo rápido desabilita o uso de memo, portanto, agilizando o processo de serialização com pickle por não gerar códigos de operação PUT supérfluos. Ele não deve ser usado com objetos autorreferenciais, fazer o contrário fará com que `Pickler` recorra infinitamente.

    Use `pickletools.optimize()` se você precisar de serializações com pickle mais compactas.

class pickle.Unpickler(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

  Recebe um arquivo binário para ler um fluxo de dados pickle.

  A versão do protocolo do pickle é detectada automaticamente, portanto, nenhum argumento de protocolo é necessário.

  O argumento file deve ter três métodos: um método read() que recebe um argumento inteiro, um método readinto() que recebe um argumento buffer e um método readline() que não requer argumentos, como na interface `io.BufferedIOBase`. Assim, file pode ser um arquivo em disco aberto para leitura binária, um objeto `io.BytesIO` ou qualquer outro objeto personalizado que atenda a esta interface.

  Os argumentos opcionais fix_imports, encoding e errors são usados para controlar o suporte de compatibilidade ao fluxo pickle gerado pelo Python 2. Se fix_imports for verdadeiro, pickle tentará mapear os nomes antigos do Python 2 para os novos nomes usados no Python 3. Os encoding e erros dizem ao pickle como decodificar instâncias de string de 8 bits capturadas pelo Python 2; o padrão é ‘ASCII’ e ‘strict’, respectivamente. O argumento encoding pode ser ‘bytes’ para ler essas instâncias de string de 8 bits como objetos de bytes. Usar `encoding='latin1'` é necessário para a desserialização com pickle de vetores NumPy e instâncias de `datetime`, `date` e `time` serializadas com pickle pelo Python 2.

  Se buffers for `None` (o padrão), todos os dados necessários para desserialização devem estar contidos no fluxo pickle. Isso significa que o argumento buffer_callback era `None` quando um `Pickler` foi instanciado (ou quando `dump()` ou `dumps()` foi chamado).

  Se buffers for `None`, deve ser um iterável de objetos habilitados para buffer que é consumido cada vez que o fluxo de serialização com pickle faz referência a uma visualização de buffer fora da banda. Esses buffers foram fornecidos em ordem para o buffer_callback de um objeto Pickler.

  Alterado na versão 3.8: O argumento buffers foi adicionado.

  load()

    Lê a representação serializada com pickle de um objeto a partir do objeto arquivo aberto fornecido no construtor e retorna a hierarquia de objeto reconstituído especificada nele. Os bytes após a representação serializada com pickle do objeto são ignorados.

  persistent_load(pid)

    Levanta um `UnpicklingError` por padrão.

    Se definido, `persistent_load()` deve retornar o objeto especificado pelo ID persistente pid. Se um ID persistente inválido for encontrado, uma `UnpicklingError` deve ser levantada.

    Consulte Persistência de objetos externos para detalhes e exemplos de usos.

    Alterado na versão 3.13: Foi adicionada a implementação padrão desse método na implementação em C da `Unpickler`.

  find_class(module, name)

    Importa module se necessário e retorna o objeto chamado name dele, onde os argumentos module e name são objetos `str`. Observe, ao contrário do que seu nome sugere, `find_class()` também é usado para encontrar funções.

    As subclasses podem substituir isso para obter controle sobre quais tipos de objetos e como eles podem ser carregados, reduzindo potencialmente os riscos de segurança. Confira Restringindo globais para detalhes.

    Levanta um evento de auditoria `pickle.find_class` com os argumentos `module`, `name`.

class pickle.PickleBuffer(buffer)

  Um invólucro para um buffer que representa dados serializáveis com pickle. buffer deve ser um objeto provedor de buffer, como um objeto bytes ou similar ou um vetor N-dimensional.

  `PickleBuffer` é ele próprio um provedor de buffer, de forma que é possível passá-lo para outras APIs que esperam um objeto provedor de buffer, como `memoryview`.

  Objetos `PickleBuffer` só podem ser serializados usando o protocolo pickle 5 ou superior. Eles são elegíveis para serialização fora de banda.

  Adicionado na versão 3.8.

  raw()

    Retorna um `memoryview` da área de memória subjacente a este buffer. O objeto retornado é um memoryview unidimensional, contíguo C com formato `B` (bytes não assinados). `BufferError` é levantada se o buffer não for contíguo C nem Fortran.

  release()

    Libera o buffer subjacente exposto pelo objeto PickleBuffer.

## O que pode ser serializado e desserializado com pickle?

Os seguintes tipos podem ser serializados com pickle:

- constantes embutidas (`None`, `True`, `False`, `Ellipsis` e `NotImplemented`);

- inteiros, números de ponto flutuante, números complexos;

- strings, bytes, bytearrays;

- tuplas, listas, conjuntos e dicionários contendo apenas objetos serializáveis com pickle;

- funções (embutidas ou definidas pelo usuário) acessíveis no nível superior de um módulo (usando `def`, não `lambda`);

- classes acessíveis no nível superior de um módulo;

- instâncias de classes cujo o resultado da chamada de `__getstate__()` seja serializável com pickle (veja a seção Serializando com pickle instâncias de classes para detalhes).

As tentativas de serializar objetos não serializáveis com pickle vão levantar a exceção `PicklingError`; quando isso acontece, um número não especificado de bytes pode já ter sido escrito no arquivo subjacente. Tentar serializar com pickle uma estrutura de dados altamente recursiva pode exceder a profundidade máxima de recursão, a `RecursionError` será levantada neste caso. Você pode aumentar este limite cuidadosamente com `sys.setrecursionlimit()`.

Observe que as funções (embutidas e definidas pelo usuário) são serializadas com pickle pelo nome qualificado, não pelo valor. [2] Isso significa que apenas o nome da função é serializado com pickle, junto com o nome do módulo e das classes contidos. Nem o código da função, nem qualquer um de seus atributos de função são serializados com pickle. Assim, o módulo de definição deve ser importável no ambiente de desserialização com pickle, e o módulo deve conter o objeto nomeado, caso contrário, uma exceção será levantada. [3]

Da mesma forma, as classes são serializadas com pickle pelo nome qualificado, portanto, aplicam-se as mesmas restrições no ambiente de desserialização com pickle. Observe que nenhum código ou dado da classe é coletado, portanto, no exemplo a seguir, o atributo de classe `attr` não é restaurado no ambiente de desserialização com pickle:

    class Foo:
        attr = 'A class attribute'

    picklestring = pickle.dumps(Foo)

Essas restrições são a razão pela qual as funções e classes serializáveis com pickle devem ser definidas no nível superior de um módulo.

Da mesma forma, quando as instâncias da classe são serializadas com pickle, o código e os dados de sua classe não são serializados junto com elas. Apenas os dados da instância são serializados com pickle. Isso é feito de propósito para que você possa corrigir bugs em uma classe ou adicionar métodos à classe e ainda carregar objetos que foram criados com uma versão anterior da classe. Se você planeja ter objetos de longa duração que verão muitas versões de uma classe, pode valer a pena colocar um número de versão nos objetos para que as conversões adequadas possam ser feitas pelo método `__setstate__()` da classe.

## Serializando com pickle instâncias de classes

Nesta seção, descrevemos os mecanismos gerais disponíveis para você definir, personalizar e controlar como as instâncias de classe são serializadas e desserializadas com pickle.

Na maioria dos casos, nenhum código adicional é necessário para tornar as instâncias serializáveis com pickle. Por padrão, o pickle recuperará a classe e os atributos de uma instância por meio de introspecção. Quando uma instância de classe não está serializada com pickle, seu método `__init__()` geralmente não é invocado. O comportamento padrão primeiro cria uma instância não inicializada e, em seguida, restaura os atributos salvos. O código a seguir mostra uma implementação desse comportamento:

    def save(obj):
        return (obj.__class__, obj.__dict__)

    def restore(cls, attributes):
        obj = cls.__new__(cls)
        obj.__dict__.update(attributes)
        return obj

As classes podem alterar o comportamento padrão, fornecendo um ou vários métodos especiais:

object.__getnewargs_ex__()

  Nos protocolos 2 e mais recentes, as classes que implementam o método `__getnewargs_ex__()` podem ditar os valores passados para o método `__new__()` após a desserialização com pickle. O método deve retornar um par `(args, kwargs)` onde args é uma tupla de argumentos posicionais e kwargs um dicionário de argumentos nomeados para construir o objeto. Esses serão passados para o método `__new__()` após a desserialização com pickle.

  Você deve implementar este método se o método `__new__()` de sua classe requer argumentos somente-nomeados. Caso contrário, é recomendado para compatibilidade implementar `__getnewargs__()`.

  Alterado na versão 3.6: `__getnewargs_ex__()` é agora usado em protocolos 2 e 3.

object.__getnewargs__()

  Este método serve a um propósito semelhante ao de `__getnewargs_ex__()`, mas tem suporte apenas a argumentos posicionais. Ele deve retornar uma tupla de argumentos `args` que serão passados para o método `__new__()` após a desserialização com pickle.

  `__getnewargs__()` não será chamado se `__getnewargs_ex__()` estiver definido.

  Alterado na versão 3.6: Antes do Python 3.6, `__getnewargs__()` era chamado em vez de `__getnewargs_ex__()` nos protocolos 2 e 3.

object.__getstate__()

  Classes podem influenciar ainda mais como suas instâncias são serializadas com pickle, substituindo o método `__getstate__()`. Ele é chamado e o objeto retornado é serializado com pickle como o conteúdo da instância, em vez de um estado padrão. Existem vários casos:

  - Para uma classe que não possui instância `__dict__` e não possui `__slots__`, o estado padrão é `None`.

  - Para uma classe que não uma possui instância `__dict__` nem `__slots__`, o estado padrão é `self.__dict__`.

  - Para uma classe que possui uma instância `__dict__` e `__slots__`, o estado padrão é uma tupla consistindo de dois dicionários: `self.__dict__`, e um dicionário de mapeamento de nomes de slot para valores de slot. Apenas os slots que possuem um valor são incluídos neste último.

  - Para uma classe que possui `__slots__` e nenhuma `__dict__` de instância, o estado padrão é uma tupla cujo primeiro item é `None` e cujo segundo item é um dicionário mapeando os nomes dos slots para os valores dos slots descritos no tópico anterior.

  Alterado na versão 3.11: Adicionada a implementação padrão do método `__getstate__()` na classe `objeto`.

object.__setstate__(state)

  Ao desserializar com pickle, se a classe define `__setstate__()`, ela é chamada com o estado não desserializado. Nesse caso, não há nenhum requisito para que o objeto de estado seja um dicionário. Caso contrário, o estado serializado com pickle deve ser um dicionário e seus itens são atribuídos ao dicionário da nova instância.

  Nota

  Se `__reduce__()` retorna um estado com valor `None` na serialização com pickle, o método `__setstate__()` não será chamado quando da desserialização com pickle.

Confira a seção Manipulação de objetos com estado para mais informações sobre como usar os métodos `__getstate__()` e `__setstate__()`.

Nota

Quando da desserialização com pickle, alguns métodos, como `__getattr__()`, `__getattribute__()` ou `__setattr__()`, podem ser chamados na instância. No caso desses métodos dependerem de alguma invariante interna ser verdadeira, o tipo deve ser implementado `__new__()` para estabelecer tal invariante, pois `__init__()` não é chamada quando da desserialização com pickle em uma instância.

Como veremos, o pickle não usa diretamente os métodos descritos acima. Na verdade, esses métodos são parte do protocolo de cópia que implementa o método especial `__reduce__()`. O protocolo de cópia fornece uma interface unificada para recuperar os dados necessários para serialização com pickle e cópia de objetos. [4]

Apesar de poderoso, implementar `__reduce__()` diretamente em sua classe é algo propenso a erro. Por este motivo, designers de classe devem usar a interface de alto nível (ou seja, `__getnewargs_ex__()`, `__getstate__()` e `__setstate__()`) sempre que possível. Vamos mostrar, porém, casos em que o uso de `__reduce__()` é a única opção ou leva a uma serialização com pickle mais eficiente, ou as ambas.

object.__reduce__()

  A interface está atualmente definida da seguinte maneira. O método `__reduce__()` não aceita nenhum argumento e deve retornar uma string ou preferencialmente uma tupla (o objeto retornado é frequentemente referido como o “valor de redução”).

  Se uma string é retornada, ela deve ser interpretada como o nome de uma variável global. Deve ser o nome local do objeto relativo ao seu módulo; o módulo pickle pesquisa o espaço de nomes do módulo para determinar o módulo do objeto. Esse comportamento é normalmente útil para singletons.

  Quando uma tupla é retornada, ela deve ter entre dois e seis itens. Os itens opcionais podem ser omitidos ou `None` pode ser fornecido como seu valor. A semântica de cada item está em ordem:

  - Um objeto chamável que será chamado para criar a versão inicial do objeto.

  - Uma tupla de argumentos para o objeto chamável. Uma tupla vazia deve ser fornecida se o chamável não aceitar nenhum argumento.

  - Opcionalmente, o estado do objeto, que será passado para o método `__setstate__()` do objeto conforme descrito anteriormente. Se o objeto não tiver tal método, o valor deve ser um dicionário e será adicionado ao atributo `__dict__` do objeto.

  - Opcionalmente, um iterador (e não uma sequência) produzindo itens sucessivos. Esses itens serão anexados ao objeto usando `obj.append(item)` ou, em lote, usando `obj.extend(list_of_items)`. Isso é usado principalmente para subclasses de lista, mas pode ser usado por outras classes, desde que tenham os métodos `append()` e `extend()` com a assinatura apropriada. (Se `append()` ou `extend()` é usado depende de qual versão do protocolo pickle é usada, bem como o número de itens a anexar, então ambos devem ser suportados.)

  - Opcionalmente, um iterador (não uma sequência) produzindo pares de valor-chave sucessivos. Esses itens serão armazenados no objeto usando `obj[chave]=valor`. Isso é usado principalmente para subclasses de dicionário, mas pode ser usado por outras classes, desde que implementem `__setitem__()`.

  - Opcionalmente, um chamável com uma assinatura `(obj, estado)`. Este chamável permite ao usuário controlar programaticamente o comportamento de atualização de estado de um objeto específico, ao invés de usar o método estático `__setstate__()` de `obj`. Se não for `None`, este chamável terá prioridade sobre o `__setstate__()` de `obj`.

    Adicionado na versão 3.8: O sexto item opcional de tupla, `(obj, estado)`, foi adicionado.

object.__reduce_ex__(protocol)

  Alternativamente, um método `__reduce_ex__()` pode ser definido. A única diferença é que este método deve ter um único argumento inteiro, a versão do protocolo. Quando definido, pickle irá preferir isso ao método `__reduce__()`. Além disso, `__reduce__()` automaticamente se torna um sinônimo para a versão estendida. O principal uso desse método é fornecer valores de redução com compatibilidade reversa para versões mais antigas do Python.

### Persistência de objetos externos

Para o benefício da persistência do objeto, o módulo `pickle` tem suporte à noção de uma referência a um objeto fora do fluxo de dados serializados com pickle. Esses objetos são referenciados por um ID persistente, que deve ser uma string de caracteres alfanuméricos (para o protocolo 0) [5] ou apenas um objeto arbitrário (para qualquer protocolo mais recente).

A resolução de tais IDs persistentes não é definida pelo módulo `pickle`; ele vai delegar esta resolução aos métodos definidos pelo usuário no selecionador e no separador, `persistent_id()` e `persistent_load()` respectivamente.

Para serializar com pickle objetos que têm um ID externo persistente, o pickler deve ter um método `persistent_id()` personalizado que recebe um objeto como um argumento e retorna `None` ou o ID persistente para esse objeto. Quando `None` é retornado, o pickler simplesmente serializa o objeto normalmente. Quando uma string de ID persistente é retornada, o pickler serializa aquele objeto, junto com um marcador para que o unpickler o reconheça como um ID persistente.

Para desserializar com pickle objetos externos, o unpickler deve ter um método `persistent_load()` personalizado que recebe um objeto de ID persistente e retorna o objeto referenciado.

Aqui está um exemplo abrangente que apresenta como o ID persistente pode ser usado para serializar com pickle objetos externos por referência.

    # Exemplo simples que mostra como o ID persistente pode ser usado
    # serializar com pickle objetos externos por referência.

    import pickle
    import sqlite3
    from collections import namedtuple

    # Classe simples que representa um registro em nosso banco de dados.
    MemoRecord = namedtuple("MemoRecord", "key, task")

    class DBPickler(pickle.Pickler):

        def persistent_id(self, obj):
            # Em vez de conservar MemoRecord como uma instância de classe regular,
            # emitimos um ID persistente.
            if isinstance(obj, MemoRecord):
                # Aqui, nosso ID persistente é simplesmente uma tupla, contendo
                # uma tag e uma chave, que se refere a um registro específico
                # no banco de dados.
                return ("MemoRecord", obj.key)
            else:
                # Se obj não tiver um ID persistente, retorna None. Significa que
                # obj precisa ser conservado como de costume.
                return None

    class DBUnpickler(pickle.Unpickler):

        def __init__(self, file, connection):
            super().__init__(file)
            self.connection = connection

        def persistent_load(self, pid):
            # Este método é invocado sempre que um ID persistente é encontrado.
            # Aqui, pid é a tupla retornada por DBPickler.
            cursor = self.connection.cursor()
            type_tag, key_id = pid
            if type_tag == "MemoRecord":
                # Busca o registro referenciado no banco de dados e retorna-o.
                cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),))
                key, task = cursor.fetchone()
                return MemoRecord(key, task)
            else:
                # Sempre levanta um erro se você puder retornar o objeto correto.
                # Caso contrário, a desserialização com pickle considerará que
                # None é o objeto referenciado pelo ID persistente.
                raise pickle.UnpicklingError("unsupported persistent object")

    def main():
        import io
        import pprint

        # Inicializa e popula nosso banco de dados.
        conn = sqlite3.connect(":memory:")
        cursor = conn.cursor()
        cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)")
        tasks = (
            'give food to fish',
            'prepare group meeting',
            'fight with a zebra',
            )
        for task in tasks:
            cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,))

        # Busca os registros a serem serializados com pickle.
        cursor.execute("SELECT * FROM memos")
        memos = [MemoRecord(key, task) for key, task in cursor]
        # Salva os registros usando nosso DBPickler personalizado.
        file = io.BytesIO()
        DBPickler(file).dump(memos)

        print("Pickled records:")
        pprint.pprint(memos)

        # Atualiza um registro, só por precaução.
        cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1")

        # Carrega os registros do fluxo de dados pickle.
        file.seek(0)
        memos = DBUnpickler(file, conn).load()

        print("Unpickled records:")
        pprint.pprint(memos)

    if __name__ == '__main__':
        main()

### Tabelas de despacho

Se alguém quiser personalizar a serialização com pickle de algumas classes sem perturbar nenhum outro código que dependa da serialização, pode-se criar um pickler com uma tabela de despacho privada.

A tabela de despacho global gerenciada pelo módulo `copyreg` está disponível como `copyreg.dispatch_table`. Portanto, pode-se escolher usar uma cópia modificada de `copyreg.dispatch_table` como uma tabela de despacho privada.

Por exemplo

    f = io.BytesIO()
    p = pickle.Pickler(f)
    p.dispatch_table = copyreg.dispatch_table.copy()
    p.dispatch_table[SomeClass] = reduce_SomeClass

cria uma instância de `pickle.Pickler` com uma tabela de despacho privada que trata a classe `SomeClass` especialmente. Alternativamente, o código

    class MyPickler(pickle.Pickler):
        dispatch_table = copyreg.dispatch_table.copy()
        dispatch_table[SomeClass] = reduce_SomeClass
    f = io.BytesIO()
    p = MyPickler(f)

faz o mesmo, mas todas as instâncias de `MyPickler` compartilharão por padrão a tabela de despacho privada. Por outro lado, o código

    copyreg.pickle(SomeClass, reduce_SomeClass)
    f = io.BytesIO()
    p = pickle.Pickler(f)

modifica a tabela de despacho global compartilhada por todos os usuários do módulo `copyreg`.

### Manipulação de objetos com estado

Aqui está um exemplo que mostra como modificar o comportamento de serialização com pickle de uma classe. A classe `TextReader` abaixo abre um arquivo texto e retorna o número da linha e o conteúdo da linha cada vez que seu método `readline()` é chamado. Se uma instância de `TextReader` for selecionada, todos os atributos exceto o membro do objeto arquivo são salvos. Quando a instância é removida, o arquivo é reaberto e a leitura continua a partir do último local. Os métodos `__setstate__()` e `__getstate__()` são usados para implementar este comportamento.

    class TextReader:
        """Exibe e numera linhas em um arquivo texto."""

        def __init__(self, filename):
            self.filename = filename
            self.file = open(filename)
            self.lineno = 0

        def readline(self):
            self.lineno += 1
            line = self.file.readline()
            if not line:
                return None
            if line.endswith('\n'):
                line = line[:-1]
            return "%i: %s" % (self.lineno, line)

        def __getstate__(self):
            # Copia o estado do objeto de self.__dict__, que
            # contém todos os nossos atributos de instância.
            # Sempre use o método dict.copy() para evitar
            # modificar o estado original.
            state = self.__dict__.copy()
            # Remove as entradas não serializáveis com pickle.
            del state['file']
            return state

        def __setstate__(self, state):
            # Restaura os atributos da instância (isto é, filename e lineno).
            self.__dict__.update(state)
            # Restaura o estado do arquivo aberto anteriormente.
            # Para fazer isso, precisamos reabri-lo e ler dele até
            # a contagem de linha ser restaurada.
            file = open(self.filename)
            for _ in range(self.lineno):
                file.readline()
            # Ao final, salva o arquivo.
            self.file = file

Um exemplo de uso pode ser algo assim:

    >>> reader = TextReader("hello.txt")
    >>> reader.readline()
    '1: Hello world!'
    >>> reader.readline()
    '2: I am line number two.'
    >>> new_reader = pickle.loads(pickle.dumps(reader))
    >>> new_reader.readline()
    '3: Goodbye!'

## Redução personalizada para tipos, funções e outros objetos

Adicionado na versão 3.8.

Às vezes, `dispatch_table` pode não ser flexível o suficiente. Em particular, podemos querer personalizar a serialização com pickle com base em outro critério que não o tipo do objeto, ou podemos personalizar a serialização com pickle de funções e classes.

Para esses casos, é possível criar uma subclasse da classe `Pickler` e implementar um método `reducer_override()`. Este método pode retornar uma tupla de redução arbitrária (veja `__reduce__()`). Ele pode, alternativamente, retornar `NotImplemented` para retornar ao comportamento tradicional.

Se `dispatch_table` e `reducer_override()` forem definidos, o método `reducer_override()` tem prioridade.

Nota

Por motivos de desempenho, `reducer_override()` não pode ser chamado para os seguintes objetos: `None`, `True`, `False`, e as instâncias exatas de `int`, `float`, `bytes`, `str`, `dict`, `set`, `frozenset`, `list` e `tuple`.

Aqui está um exemplo simples onde permitimos serialização com pickle e reconstrução de uma determinada classe:

    import io
    import pickle

    class MyClass:
        my_attribute = 1

    class MyPickler(pickle.Pickler):
        def reducer_override(self, obj):
            """Redutor personalizado para MyClass."""
            if getattr(obj, "__name__", None) == "MyClass":
                return type, (obj.__name__, obj.__bases__,
                              {'my_attribute': obj.my_attribute})
            else:
                # Para qualquer outro objeto, recorre à redução de costume
                return NotImplemented

    f = io.BytesIO()
    p = MyPickler(f)
    p.dump(MyClass)

    del MyClass

    unpickled_class = pickle.loads(f.getvalue())

    assert isinstance(unpickled_class, type)
    assert unpickled_class.__name__ == "MyClass"
    assert unpickled_class.my_attribute == 1

## Buffers fora da banda

Adicionado na versão 3.8.

Em alguns contextos, o módulo `pickle` é usado para transferir grandes quantidades de dados. Portanto, pode ser importante minimizar o número de cópias de memória para preservar o desempenho e o consumo de recursos. No entanto, a operação normal do módulo `pickle`, à medida que transforma uma estrutura semelhante a um gráfico de objetos em um fluxo sequencial de bytes, envolve intrinsecamente a cópia de dados de e para o fluxo pickle.

Esta restrição pode ser evitada se tanto o fornecedor (a implementação dos tipos de objetos a serem transferidos) e o consumidor (a implementação do sistema de comunicações) tiverem suporte aos recursos de transferência fora de banda fornecidos pelo protocolo pickle 5 e superior.

### API de provedor

Os grandes objetos de dados a serem serializados com pickle devem implementar um método `__reduce_ex__()` especializado para o protocolo 5 e superior, que retorna uma instância `PickleBuffer` (em vez de, por exemplo, um objeto `bytes`) para quaisquer dados grandes.

Um objeto `PickleBuffer` sinaliza que o buffer subjacente é elegível para transferência de dados fora de banda. Esses objetos permanecem compatíveis com o uso normal do módulo `pickle`. No entanto, os consumidores também podem optar por dizer ao `pickle` que eles irão lidar com esses buffers por conta própria.

### API de consumidor

Um sistema de comunicação pode permitir o manuseio personalizado dos objetos `PickleBuffer` gerados ao serializar um grafo de objeto.

No lado emissor, é necessário passar um argumento buffer_callback para `Pickler` (ou para a função `dump()` ou `dumps()`), que será chamada com cada `PickleBuffer` gerado durante a serialização com pickle do grafo do objeto. Os buffers acumulados pelo buffer_callback não verão seus dados copiados no fluxo pickle, apenas um marcador barato será inserido.

No lado receptor, é necessário passar um argumento buffers para `Unpickler` (ou para a função `load()` ou `load()`), que é um iterável dos buffers que foram passado para buffer_callback. Esse iterável deve produzir buffers na mesma ordem em que foram passados para buffer_callback. Esses buffers fornecerão os dados esperados pelos reconstrutores dos objetos cuja serialização com pickle produziu os objetos `PickleBuffer` originais.

Entre o lado emissor e o lado receptor, o sistema de comunicações está livre para implementar seu próprio mecanismo de transferência para buffers fora de banda. As otimizações potenciais incluem o uso de memória compartilhada ou compactação dependente do tipo de dados.

### Exemplo

Aqui está um exemplo trivial onde implementamos uma subclasse de `bytearray` capaz de participar de serialização com pickle de buffer fora de banda:

    class ZeroCopyByteArray(bytearray):

        def __reduce_ex__(self, protocol):
            if protocol >= 5:
                return type(self)._reconstruct, (PickleBuffer(self),), None
            else:
                # PickleBuffer é proibido no pickle nos protocolos <= 4.
                return type(self)._reconstruct, (bytearray(self),)

        @classmethod
        def _reconstruct(cls, obj):
            with memoryview(obj) as m:
                # Obtém um controle sobre o objeto buffer original
                obj = m.obj
                if type(obj) is cls:
                    # O objeto do buffer original é um ZeroCopyByteArray,
                    # retorna-o como está.
                    return obj
                else:
                    return cls(obj)

O reconstrutor (o método de classe `_reconstruct`) retorna o objeto de fornecimento do buffer se ele tiver o tipo correto. Esta é uma maneira fácil de simular o comportamento de cópia zero neste exemplo de brinquedo.

Do lado consumidor, podemos serializar com pickle esses objetos da maneira usual, que quando não serializados nos dará uma cópia do objeto original:

    b = ZeroCopyByteArray(b"abc")
    data = pickle.dumps(b, protocol=5)
    new_b = pickle.loads(data)
    print(b == new_b)  # True
    print(b is new_b)  # False: uma cópia foi feita

Mas se passarmos um buffer_callback e, em seguida, retornarmos os buffers acumulados ao desserializar, seremos capazes de recuperar o objeto original:

    b = ZeroCopyByteArray(b"abc")
    buffers = []
    data = pickle.dumps(b, protocol=5, buffer_callback=buffers.append)
    new_b = pickle.loads(data, buffers=buffers)
    print(b == new_b)  # True
    print(b is new_b)  # True: nenhuma cópia foi feita

Este exemplo é limitado pelo fato de que `bytearray` aloca sua própria memória: você não pode criar uma instância de `bytearray` que é apoiada pela memória de outro objeto. No entanto, tipos de dados de terceiros, como arrays de NumPy, não têm essa limitação e permitem o uso de serialização com pickle de cópia zero (ou fazer o mínimo de cópias possível) ao transferir entre processos ou sistemas distintos.

Ver também

PEP 574 – Protocolo de Pickle 5 com buffers de dados fora da banda

## Restringindo globais

Por padrão, a desserialização com pickle importará qualquer classe ou função que encontrar nos dados pickle. Para muitos aplicativos, esse comportamento é inaceitável, pois permite que o unpickler importe e invoque código arbitrário. Basta considerar o que este fluxo de dados pickle feito à mão faz quando carregado:

    >>> import pickle
    >>> pickle.loads(b"cos\nsystem\n(S'echo hello world'\ntR.")
    hello world
    0

Neste exemplo, o unpickler importa a função `os.system()` e então aplica o argumento string “echo hello world”. Embora este exemplo seja inofensivo, não é difícil imaginar um que possa danificar seu sistema.

Por esta razão, você pode querer controlar o que é desserializado com pickle personalizando `Unpickler.find_class()`. Ao contrário do que seu nome sugere, `Unpickler.find_class()` é chamado sempre que um global (ou seja, uma classe ou uma função) é solicitado. Assim, é possível proibir completamente os globais ou restringi-los a um subconjunto seguro.

Aqui está um exemplo de um unpickler que permite que apenas algumas classes seguras do módulo `builtins` sejam carregadas:

    import builtins
    import io
    import pickle

    safe_builtins = {
        'range',
        'complex',
        'set',
        'frozenset',
        'slice',
    }

    class RestrictedUnpickler(pickle.Unpickler):

        def find_class(self, module, name):
            # Só permite classes seguras de bultins.
            if module == "builtins" and name in safe_builtins:
                return getattr(builtins, name)
            # Proíbe todo o resto.
            raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
                                         (module, name))

    def restricted_loads(s):
        """Função auxiliar análoga a pickle.loads()."""
        return RestrictedUnpickler(io.BytesIO(s)).load()

Um exemplo de uso do nosso unpickler funcionando como esperado:

    >>> restricted_loads(pickle.dumps([1, 2, range(15)]))
    [1, 2, range(0, 15)]
    >>> restricted_loads(b"cos\nsystem\n(S'echo hello world'\ntR.")
    Traceback (most recent call last):
      ...
    pickle.UnpicklingError: global 'os.system' is forbidden
    >>> restricted_loads(b'cbuiltins\neval\n'
    ...                  b'(S\'getattr(__import__("os"), "system")'
    ...                  b'("echo hello world")\'\ntR.')
    Traceback (most recent call last):
      ...
    pickle.UnpicklingError: global 'builtins.eval' is forbidden

Como nossos exemplos mostram, você deve ter cuidado com o que permite que seja desserializado com pickle. Portanto, se a segurança é uma preocupação, você pode querer considerar alternativas como a API de marshalling em `xmlrpc.client` ou soluções de terceiros.

## Desempenho

Versões recentes do protocolo pickle (do protocolo 2 em diante) apresentam codificações binárias eficientes para vários recursos comuns e tipos embutidos. Além disso, o módulo `pickle` tem um otimizador transparente escrito em C.

## Exemplos

Para código mais simples, use as funções `dump()` e `load()`.

    import pickle

    # Uma coleção arbitrária de objetos aceitos por pickle.
    data = {
        'a': [1, 2.0, 3+4j],
        'b': ("character string", b"byte string"),
        'c': {None, True, False}
    }

    with open('data.pickle', 'wb') as f:
        # Serializa com pickle o dicionário 'data' usando
        # o protocolo mais alto disponível.
        pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

O exemplo a seguir lê os dados resultantes em serializados com pickle.

    import pickle

    with open('data.pickle', 'rb') as f:
        # A versão do protocolo utilizada é detectada automaticamente,
        # portanto não precisamos especificá-la.
        data = pickle.load(f)

Ver também

Módulo `copyreg`

  Registro de construtor de interface Pickle para tipos de extensão.

Módulo `pickletools`

  Ferramentas para trabalhar e analisar dados serializados com pickle.

Módulo `shelve`

  Banco de dados indexado de objetos; usa `pickle`.

Módulo `copy`

  Cópia rasa e cópia profunda de objeto.

Módulo `marshal`

  Serialização de alto desempenho de tipos embutidos.

Notas de rodapé

[1]

Não confunda isso com o módulo `marshal`

[2]

É por isso que funções `lambda` não podem ser serializadas com pickle: todas as funções `lambda` compartilham o mesmo nome: `<lambda>`.

[3]

A exceção levantada provavelmente será uma `ImportError` ou uma `AttributeError`, mas poderia ser outra coisa.

[4]

O módulo `copy` usa este protocolo para operações de cópia rasa e cópia profunda.

[5]

A limitação de caracteres alfanuméricos se deve ao fato de que os IDs persistentes, no protocolo 0, serem delimitados pelo caractere de nova linha. Portanto, se qualquer tipo de caractere de nova linha ocorrer em IDs persistentes, os dados resultantes da serialização com pickle se tornarão ilegíveis.