12.1. "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 byte ou similar*) é
convertido de volta em uma hierarquia de objetos. Pickling (e
unpickling) é alternativamente conhecido como "serialização",
"marshalling" [1] ou "flattening"; no entanto, para evitar confusão,
os termos usados ​​aqui são "pickling" e "unpickling".

Aviso:

  The "pickle" module is not secure against erroneous or maliciously
  constructed data.  Never unpickle data received from an untrusted or
  unauthenticated source.


12.1.1. Relacionamento com outros módulos Python
================================================


12.1.1.1. 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:

* O módulo "pickle" mantém o controle dos objetos que já serializou,
  para que referências posteriores ao mesmo objeto não sejam
  serializadas novamente. "marshal" não faz isso.

  Isso tem implicações tanto para objetos recursivos quanto para
  compartilhamento de objetos. Objetos recursivos são objetos que
  contêm referências a si mesmos. Eles não são tratados pelo marshal
  e, de fato, tentar usar marshal em objetos recursivos irá travar seu
  interpretador Python. O compartilhamento de objetos ocorre quando há
  várias referências ao mesmo objeto em locais diferentes na
  hierarquia de objetos sendo serializados. "pickle" armazena tais
  objetos apenas uma vez, e garante que todas as outras referências
  apontem para a cópia mestre. Os objetos compartilhados permanecem
  compartilhados, o que pode ser muito importante para objetos
  mutáveis.

* "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.

* The "marshal" serialization format is not guaranteed to be portable
  across Python versions.  Because its primary job in life is to
  support ".pyc" files, the Python implementers reserve the right to
  change the serialization format in non-backwards compatible ways
  should the need arise. The "pickle" serialization format is
  guaranteed to be backwards compatible across Python releases.


12.1.1.2. 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, by default, can only represent a subset of the Python built-in
  types, and no custom classes; pickle can represent an extremely
  large number of Python types (many of them automatically, by clever
  usage of Python's introspection facilities; complex cases can be
  tackled by implementing specific object APIs).

Ver também:

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


12.1.2. Formato de fluxo de dados
=================================

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

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.

There are currently 5 different protocols which can be used for
pickling. The higher the protocol used, the more recent the version of
Python needed to read the pickle produced.

* 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 separação muito mais eficiente de *classes estilo novo*.
  Consulte **PEP 307** para obter informações sobre as melhorias
  trazidas pelo protocolo 2.

* Protocol version 3 was added in Python 3.0.  It has explicit support
  for "bytes" objects and cannot be unpickled by Python 2.x.  This is
  the default protocol, and the recommended protocol when
  compatibility with other Python 3 versions is required.

* Protocol version 4 was added in Python 3.4.  It adds support for
  very large objects, pickling more kinds of objects, and some data
  format optimizations.  Refer to **PEP 3154** for information about
  improvements brought by protocol 4.

Nota:

  A serialização é uma noção mais primitiva do que a persistência;
  embora o "pickle" leia e escreva objetos de 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 fazer
  pickle e unpickle de objetos em arquivos de banco de dados no estilo
  DBM.


12.1.3. 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

   An integer, the default protocol version used for pickling.  May be
   less than "HIGHEST_PROTOCOL".  Currently the default protocol is 3,
   a new protocol designed for Python 3.

O módulo "pickle" fornece as seguintes funções para tornar o processo
de pickling mais conveniente:

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

   Write a pickled representation of *obj* to the open *file object*
   *file*. This is equivalent to "Pickler(file, protocol).dump(obj)".

   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.

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

   Return the pickled representation of the object as a "bytes"
   object, instead of writing it to a file.

   Arguments *protocol* and *fix_imports* have the same meaning as in
   "dump()".

pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")

   Read a pickled object representation from the open *file object*
   *file* and return the reconstituted object hierarchy specified
   therein. This is equivalent to "Unpickler(file).load()".

   The protocol version of the pickle is detected automatically, so no
   protocol argument is needed.  Bytes past the pickled object's
   representation are ignored.

   The argument *file* must have two methods, a read() method that
   takes an integer argument, and a readline() method that requires no
   arguments.  Both methods should return bytes.  Thus *file* can be
   an on-disk file opened for binary reading, an "io.BytesIO" object,
   or any other custom object that meets this interface.

   Optional keyword arguments are *fix_imports*, *encoding* and
   *errors*, which are used to control compatibility support for
   pickle stream generated by Python 2.  If *fix_imports* is true,
   pickle will try to map the old Python 2 names to the new names used
   in Python 3.  The *encoding* and *errors* tell pickle how to decode
   8-bit string instances pickled by Python 2; these default to
   'ASCII' and 'strict', respectively.  The *encoding* can be 'bytes'
   to read these 8-bit string instances as bytes objects. Using
   "encoding='latin1'" is required for unpickling NumPy arrays and
   instances of "datetime", "date" and "time" pickled by Python 2.

pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict")

   Read a pickled object hierarchy from a "bytes" object and return
   the reconstituted object hierarchy specified therein.

   The protocol version of the pickle is detected automatically, so no
   protocol argument is needed.  Bytes past the pickled object's
   representation are ignored.

   Optional keyword arguments are *fix_imports*, *encoding* and
   *errors*, which are used to control compatibility support for
   pickle stream generated by Python 2.  If *fix_imports* is true,
   pickle will try to map the old Python 2 names to the new names used
   in Python 3.  The *encoding* and *errors* tell pickle how to decode
   8-bit string instances pickled by Python 2; these default to
   'ASCII' and 'strict', respectively.  The *encoding* can be 'bytes'
   to read these 8-bit string instances as bytes objects. Using
   "encoding='latin1'" is required for unpickling NumPy arrays and
   instances of "datetime", "date" and "time" pickled by Python 2.

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 "Exception".

exception pickle.PicklingError

   Erro levantado quando um objeto não serializável com pickle é
   encontrado por "Pickler". Herda "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
   "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.

The "pickle" module exports two classes, "Pickler" and "Unpickler":

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

   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.

   dump(obj)

      Write a pickled representation of *obj* to the open file object
      given in the constructor.

   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.

   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.

      Novo na versão 3.3.

   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")

   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.

   The argument *file* must have two methods, a read() method that
   takes an integer argument, and a readline() method that requires no
   arguments.  Both methods should return bytes.  Thus *file* can be
   an on-disk file object opened for binary reading, an "io.BytesIO"
   object, or any other custom object that meets this interface.

   Optional keyword arguments are *fix_imports*, *encoding* and
   *errors*, which are used to control compatibility support for
   pickle stream generated by Python 2.  If *fix_imports* is true,
   pickle will try to map the old Python 2 names to the new names used
   in Python 3.  The *encoding* and *errors* tell pickle how to decode
   8-bit string instances pickled by Python 2; these default to
   'ASCII' and 'strict', respectively.  The *encoding* can be 'bytes'
   to read these 8-bit string instances as bytes objects.

   load()

      Read a pickled object representation from the open file object
      given in the constructor, and return the reconstituted object
      hierarchy specified therein.  Bytes past the pickled object's
      representation are ignored.

   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.

   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
      >>:classe:`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.


12.1.4. O que pode ser serializado e desserializado com pickle?
===============================================================

Os seguintes tipos podem ser serializados com pickle:

* "None", "True", e "False"

* 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 definidas no nível superior de um módulo (usando "def", não
  "lambda")

* funções embutidas definidas no nível superior de um módulo

* classes que são definidas no nível superior de um módulo

* instâncias de classes cujo "__dict__" ou 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 por referência de nome "totalmente
qualificado", não por valor. [2] Isso significa que apenas o nome da
função é serializado com pickle, junto com o nome do módulo no qual a
função está definida. 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 por referência
nomeada, 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 propositalmente, 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.


12.1.5. 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 load(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__()

   As classes podem influenciar ainda mais como suas instâncias são
   serializadas com pickle; se a classe define o método
   "__getstate__()", ele é chamado e o objeto retornado é serializado
   com pickle como o conteúdo da instância, ao invés do conteúdo do
   dicionário da instância. Se o método "__getstate__()" estiver
   ausente, o "__dict__" da instância é serializado com pickle como de
   costume.

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 "__getstate__()" retornar um valor falso, 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:

  At unpickling time, some methods like "__getattr__()",
  "__getattribute__()", or "__setattr__()" may be called upon the
  instance.  In case those methods rely on some internal invariant
  being true, the type should implement "__getnewargs__()" or
  "__getnewargs_ex__()" to establish such an invariant; otherwise,
  neither "__new__()" nor "__init__()" will be called.

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.

   When a tuple is returned, it must be between two and five items
   long. Optional items can either be omitted, or "None" can be
   provided as their value.  The semantics of each item are in order:

   * 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(lista_de_itens)". 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__()".

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.


12.1.5.1. 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).

The resolution of such persistent IDs is not defined by the "pickle"
module; it will delegate this resolution to the user defined methods
on the pickler and unpickler, "persistent_id()" and
"persistent_load()" respectively.

To pickle objects that have an external persistent id, the pickler
must have a custom "persistent_id()" method that takes an object as an
argument and returns either "None" or the persistent id for that
object. When "None" is returned, the pickler simply pickles the object
as normal. When a persistent ID string is returned, the pickler will
pickle that object, along with a marker so that the unpickler will
recognize it as a persistent ID.

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.

   # Simple example presenting how persistent ID can be used to pickle
   # external objects by reference.

   import pickle
   import sqlite3
   from collections import namedtuple

   # Simple class representing a record in our database.
   MemoRecord = namedtuple("MemoRecord", "key, task")

   class DBPickler(pickle.Pickler):

       def persistent_id(self, obj):
           # Instead of pickling MemoRecord as a regular class instance, we emit a
           # persistent ID.
           if isinstance(obj, MemoRecord):
               # Here, our persistent ID is simply a tuple, containing a tag and a
               # key, which refers to a specific record in the database.
               return ("MemoRecord", obj.key)
           else:
               # If obj does not have a persistent ID, return None. This means obj
               # needs to be pickled as usual.
               return None


   class DBUnpickler(pickle.Unpickler):

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

       def persistent_load(self, pid):
           # This method is invoked whenever a persistent ID is encountered.
           # Here, pid is the tuple returned by DBPickler.
           cursor = self.connection.cursor()
           type_tag, key_id = pid
           if type_tag == "MemoRecord":
               # Fetch the referenced record from the database and return it.
               cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),))
               key, task = cursor.fetchone()
               return MemoRecord(key, task)
           else:
               # Always raises an error if you cannot return the correct object.
               # Otherwise, the unpickler will think None is the object referenced
               # by the persistent ID.
               raise pickle.UnpicklingError("unsupported persistent object")


   def main():
       import io
       import pprint

       # Initialize and populate our database.
       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,))

       # Fetch the records to be pickled.
       cursor.execute("SELECT * FROM memos")
       memos = [MemoRecord(key, task) for key, task in cursor]
       # Save the records using our custom DBPickler.
       file = io.BytesIO()
       DBPickler(file).dump(memos)

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

       # Update a record, just for good measure.
       cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1")

       # Load the records from the pickle data stream.
       file.seek(0)
       memos = DBUnpickler(file, conn).load()

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


   if __name__ == '__main__':
       main()


12.1.5.2. 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" irão por padrão
compartilhar a mesma tabela de despacho. O código equivalente usando o
módulo "copyreg" é

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


12.1.5.3. 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" 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:
       """Print and number lines in a text file."""

       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):
           # Copy the object's state from self.__dict__ which contains
           # all our instance attributes. Always use the dict.copy()
           # method to avoid modifying the original state.
           state = self.__dict__.copy()
           # Remove the unpicklable entries.
           del state['file']
           return state

       def __setstate__(self, state):
           # Restore instance attributes (i.e., filename and lineno).
           self.__dict__.update(state)
           # Restore the previously opened file's state. To do so, we need to
           # reopen it and read from it until the line count is restored.
           file = open(self.filename)
           for _ in range(self.lineno):
               file.readline()
           # Finally, save the file.
           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!'


12.1.6. 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):
           # Only allow safe classes from builtins.
           if module == "builtins" and name in safe_builtins:
               return getattr(builtins, name)
           # Forbid everything else.
           raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
                                        (module, name))

   def restricted_loads(s):
       """Helper function analogous to 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.


12.1.7. Performance
===================

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.


12.1.8. Exemplos
================

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

   import pickle

   # An arbitrary collection of objects supported by pickle.
   data = {
       'a': [1, 2.0, 3, 4+6j],
       'b': ("character string", b"byte string"),
       'c': {None, True, False}
   }

   with open('data.pickle', 'wb') as f:
       # Pickle the 'data' dictionary using the highest protocol available.
       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:
       # The protocol version used is detected automatically, so we do not
       # have to specify it.
       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] This is why "lambda" functions cannot be pickled:  all "lambda"
    functions share the same name:  "<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 dos 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, o pickle resultante se tornará
    ilegível.
