7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
Advertisement
  1. Code
  2. Python

Serialização e Desserialização de Objetos do Python: Parte 1

Scroll to top
Read Time: 7 mins

Portuguese (Português) translation by Erick Patrick (you can also view the original English article)

Serialização de deserialização de objetos em Python é um aspecto importante de qualquer programa não trivial. Quando em Python se salvar algo em arquivo, ler um arquivo de configuração ou se responder a uma requisição HTTP, realizamos serialização e deserialização de objetos.

Para alguns, serialização e deserialização são as coisas mais chatas do mundo. Quem se importa com todos esses formatos e protocolos? Só queremos persistir ou transmitir alguns objetos Python e obtê-los de volta intactos depois.

É uma maneira bem saudável de ver o mundo em um nível conceitual. Mas, a nível pragmático, o esquema, formato ou protocolo de serialização que escolhermos determinará o quão rápido os programas executam, quão seguros são, quanta liberdade para manter seu estado e o quão bem interoperará com outros sistemas.

O motivo de tantas opção é que diferentes circunstâncias clamam por soluçõe diferentes. Não existe "solução de tamanho único". Nesse tutorial de duas partes, mostraremos os prós e contras dos esquemas de serialização e deserialização, assim como seus usos, e proveremos guias para a escolha certa para um determinado caso.

Exemplos Executáveis

A seguir, serializaremos e deserializaremos os mesmos grafos de objetos Python usando serializadores diferentes. Para evitar repetição, definiremos os grafos de objeto aqui.

Grafo de Objetos Simples

Grafo de objeto simples é um dicionário contendo: lista de inteiros, cadeia de caracters, ponto flutuante, booleano e None.

Grafo de Objetos Complexos

Gráfo de Objeto Complexo é um dicionário com: objeto datetime, uma instância de classe definida por usuário com um atributo self.simple, que é um gráfo de objeto simples.

Pickle

Pickle é o primeiro. É o formato de serialização de objetos nativo do Python. Sua interface provê quatro métodos: dump, dumps, load e loads. O dump() serializa em um arquivo aberto (objeto do tipo file). O dumps() serializa para uma cadeia de caracteres. O load() deserializa de um objeto aberto do tipo file. O loads() deserializa de uma cadeia de caracteres.

Pickle suporta, por padrão, um protocolo textual, mas também um protocolo binário, mais eficiente, mas não legível (que é útil em depuração).

Eis como serializa um objeto de grafo Python para uma cadeia de caracteres e para um arquivo, ambos com protoclos.

A representação binária parece maior, mas é uma ilusão devido sua apresentação. Ao salvar em um arquivo, o protocolo textual é 130 bytes, enquanto o binário só 85 bytes.

Deserialização é tão fácil quanto:

Note que o pickle descobre automaticamente o protocolo. Não é preciso especificá-lo, nem mesmo para o binário.

Deserializar de um arquivo é tão fácil quanto. Basta prover um arquivo aberto.

De acordo com a documentação, é preciso abrir arquivos binários do pickle no modo 'rb', mas, como se vê, funciona do mesmo jeito.

Vejamos como o pickle lida com grafos de objeto complexos.

A eficiência do protocolo binário é ainda maior com grafos de objetos complexos.

JSON

JSON (JavaScript Object Notation) faz parte da biblioteca padrão do Python desde a versão 2.5. Consideramo-no um formato nativo, agora. É um formato baseado em texto e é o rei não oficial da web, em termos de serialização de objetos. Seu sistema de tipos imita o do JavaScript, logo é bem limitado.

Serializemos e deserializemos um grafo de objeto simples e um complexo e vejamos o que acontece. A interface é quase idêntica à interface do pickle. Temos dump(), dumps(), load() e loads(). Mas, não há protocolos a se selecionar, e há muitos argumentos opcionais para controlar o processo. Comecemos devagar, salvando um grafo de objeto simples sem quaisquer argumentos especiais:

O resultado parece bem legível, mas não há identação. Em um grande grafo de objeto, pode ser problemático. Identemos o retorno:

Muito melhor. Sigamos para o grafo de objeto complexo.

Oh! Isso não é bom! O que aconteceu? O erro diz que o objeto A não é serialização via JSON. Lembre que JSON tem um sistema de tipos bem simples e não serializa classes criadas por usuários automaticamente. Para resolver, é preciso uma subclasse de JSONEncoder, usada pelo módulo json, e implementar default(), que é chamado sempre que um codificador se depara com um objeto que não consegue serializar.

O codificador customizado converte em um grafo de objeto Python possível de codificar pelo codificador JSON. Nesse caso, temos dois objetos que requerem codificação especial: datetime e A. O codificador a seguir resolve. Cada objeto especial é converto em um dict onde a chave é o nome do tipo envolto em dunders (sublinhados duplos). Isso será importante para decodificação.

Tentemos novamente nosso codificador customizado:

Agora, sim. O grafo de objeto complexo foi serializado apropriadamente e a informação original de tipo dos componentes foi mantida nas chaves: "__A__" e "__datetime__". Se usarmos dunders nos nossos nomes, é preciso encontrar uma outra convenção para denotar tipos especiais.

Decodifiquemos o grafo de objeto complexo.

Humm, a deserialização funcionou (sem erros), mas está diferente do grafo de objeto complexo que serializamos. Algo está errado. Vejamos o grafo de objeto deserializado. Usaremos a função pprint do modulo pprint para visualizr melhor.

Ok. O problema é que o módulo JSON disconhece a classe A ou mesmo o objeto padrão datetime. Simplesmente deserializa tudo por padrão no objeto Python que casa com seu sistema de tipo. Para obter o grafo de objeto Python original, precisamos de decodificação customizada.

Não é necessária sublasse decodificador customizada. Os load() e load() provêem o parâmetro "object_hook" que permite passar uma função customizada que converte os dicionários em objetos.

Decodifiquemos usando a função decode_object() como o parâmetro 'object_hook' de loads().

Conclusão

Nessa primeira parte, aprendemos sobre o conceito geral de serialização e deserialização de objetos Python e exploramos tudo da serialiação com Pickle e JSON.

Na parte dois, veremos YAML, performance e segurança, além de resenha dos esquemas adicionais de serialização.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.