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

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

  • 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

There are fundamental differences between the pickle protocols and 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 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.

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.

  • Protocol version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes. Refer to PEP 307 for information about improvements brought by protocol 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 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 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 byte 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.

Arguments fix_imports, encoding, errors, strict and buffers have the same meaning as in the Unpickler constructor.

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

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

exception pickle.PickleError

Common base class for the other pickling exceptions. It inherits from Exception.

exception pickle.PicklingError

Error raised when an unpicklable object is encountered by Pickler. It inherits from 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

Error raised when there is a problem unpickling an object, such as a data corruption or a security violation. It inherits from 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 o retorno de 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.

dispatch_table

A pickler object’s dispatch table is a registry of reduction functions of the kind which can be declared using copyreg.pickle(). It is a mapping whose keys are classes and whose values are reduction functions. A reduction function takes a single argument of the associated class and should conform to the same interface as a __reduce__() method.

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.

reducer_override(obj)

Special reducer that can be defined in Pickler subclasses. This method has priority over any reducer in the dispatch_table. It should conform to the same interface as a __reduce__() method, and can optionally return NotImplemented to fallback on dispatch_table-registered reducers to pickle obj.

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

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

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 argumento 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 byte 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.

Novo 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:

  • built-in constants (None, True, False, Ellipsis, and NotImplemented);

  • integers, floating-point numbers, complex numbers;

  • strings, bytes, bytearrays;

  • tuples, lists, sets, and dictionaries containing only picklable objects;

  • functions (built-in and user-defined) accessible from the top level of a module (using def, not lambda);

  • classes accessible from the top level of a module;

  • instances of such classes whose the result of calling __getstate__() is picklable (see section Serializando com pickle instâncias de classes for details).

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

Note that functions (built-in and user-defined) are pickled by fully qualified name, not by value. [2] This means that only the function name is pickled, along with the name of the containing module and classes. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised. [3]

Similarly, classes are pickled by fully qualified name, so the same restrictions in the unpickling environment apply. Note that none of the class’s code or data is pickled, so in the following example the class attribute attr is not restored in the unpickling environment:

class Foo:
    attr = 'A class attribute'

picklestring = pickle.dumps(Foo)

These restrictions are why picklable functions and classes must be defined at the top level of a module.

Similarly, when class instances are pickled, their class’s code and data are not pickled along with them. Only the instance data are pickled. This is done on purpose, so you can fix bugs in a class or add methods to the class and still load objects that were created with an earlier version of the class. If you plan to have long-lived objects that will see many versions of a class, it may be worthwhile to put a version number in the objects so that suitable conversions can be made by the class’s __setstate__() method.

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.

In most cases, no additional code is needed to make instances picklable. By default, pickle will retrieve the class and the attributes of an instance via introspection. When a class instance is unpickled, its __init__() method is usually not invoked. The default behaviour first creates an uninitialized instance and then restores the saved attributes. The following code shows an implementation of this behaviour:

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 can further influence how their instances are pickled by overriding the method __getstate__(). It is called and the returned object is pickled as the contents for the instance, instead of a default state. There are several cases:

  • For a class that has no instance __dict__ and no __slots__, the default state is None.

  • For a class that has an instance __dict__ and no __slots__, the default state is self.__dict__.

  • For a class that has an instance __dict__ and __slots__, the default state is a tuple consisting of two dictionaries: self.__dict__, and a dictionary mapping slot names to slot values. Only slots that have a value are included in the latter.

  • For a class that has __slots__ and no instance __dict__, the default state is a tuple whose first item is None and whose second item is a dictionary mapping slot names to slot values described in the previous bullet.

Alterado na versão 3.11: Added the default implementation of the __getstate__() method in the object class.

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

If __reduce__() returns a state with value None at pickling, the __setstate__() method will not be called upon unpickling.

Refer to the section Manipulação de objetos com estado for more information about how to use the methods __getstate__() and __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 __new__() to establish such an invariant, as __init__() is not called when unpickling an instance.

As we shall see, pickle does not use directly the methods described above. In fact, these methods are part of the copy protocol which implements the __reduce__() special method. The copy protocol provides a unified interface for retrieving the data necessary for pickling and copying objects. [4]

Although powerful, implementing __reduce__() directly in your classes is error prone. For this reason, class designers should use the high-level interface (i.e., __getnewargs_ex__(), __getstate__() and __setstate__()) whenever possible. We will show, however, cases where using __reduce__() is the only option or leads to more efficient pickling or both.

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.

  • Optionally, an iterator (and not a sequence) yielding successive items. These items will be appended to the object either using obj.append(item) or, in batch, using obj.extend(list_of_items). This is primarily used for list subclasses, but may be used by other classes as long as they have append and extend methods with the appropriate signature. (Whether append() or extend() is used depends on which pickle protocol version is used as well as the number of items to append, so both must be supported.)

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

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

# 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()

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.

The global dispatch table managed by the copyreg module is available as copyreg.dispatch_table. Therefore, one may choose to use a modified copy of copyreg.dispatch_table as a private dispatch table.

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)

does the same but all instances of MyPickler will by default share the private dispatch table. On the other hand, the code

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

modifies the global dispatch table shared by all users of the copyreg module.

Manipulação de objetos com estado

Here’s an example that shows how to modify pickling behavior for a class. The TextReader class below opens a text file, and returns the line number and line contents each time its readline() method is called. If a TextReader instance is pickled, all attributes except the file object member are saved. When the instance is unpickled, the file is reopened, and reading resumes from the last location. The __setstate__() and __getstate__() methods are used to implement this behavior.

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!'

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

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

For those cases, it is possible to subclass from the Pickler class and implement a reducer_override() method. This method can return an arbitrary reduction tuple (see __reduce__()). It can alternatively return NotImplemented to fallback to the traditional behavior.

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):
        """Custom reducer for MyClass."""
        if getattr(obj, "__name__", None) == "MyClass":
            return type, (obj.__name__, obj.__bases__,
                          {'my_attribute': obj.my_attribute})
        else:
            # For any other object, fallback to usual reduction
            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

Novo 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

The large data objects to be pickled must implement a __reduce_ex__() method specialized for protocol 5 and higher, which returns a PickleBuffer instance (instead of e.g. a bytes object) for any large data.

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 is forbidden with pickle protocols <= 4.
            return type(self)._reconstruct, (bytearray(self),)

    @classmethod
    def _reconstruct(cls, obj):
        with memoryview(obj) as m:
            # Get a handle over the original buffer object
            obj = m.obj
            if type(obj) is cls:
                # Original buffer object is a ZeroCopyByteArray, return it
                # as-is.
                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: a copy was made

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: no copy was made

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):
        # 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()

A sample usage of our unpickler working as intended:

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

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.

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+4j],
    '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é