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

Serialización y deserialización de objetos Python: Parte 1

Scroll to top
Read Time: 8 mins

Spanish (Español) translation by Andrea Jiménez (you can also view the original English article)

La serialización y deserialización de objetos Python es un aspecto importante de cualquier programa no trivial. Si guardas algo en un archivo en Python, si lees un archivo de configuración o si respondes a una solicitud HTTP, puedes serializar y deserializar objetos.

En cierto sentido, la serialización y la deserialización son las cosas más aburridas del mundo. ¿A quién le importan todos los formatos y protocolos? Solo deseas conservar o transmitir algunos objetos de Python y recuperarlos intactos más tarde.

Esta es una forma muy saludable de ver el mundo a nivel conceptual. Pero, a nivel pragmático, el esquema, formato o protocolo de serialización que elijas puede determinar qué tan rápido se ejecuta tu programa, qué tan seguro es, cuánta libertad tienes para mantener tu estado y qué tan bien vas a interoperar con otros sistemas.

La razón por la que hay tantas opciones es que diferentes circunstancias requieren diferentes soluciones. No hay "un tamaño que se adapte a todos". En este tutorial de dos partes, repasaré los pros y los contras de los esquemas de serialización y deserialización más exitosos, mostraré cómo usarlos y proporcionaré pautas para elegir entre ellos cuando se enfrente a un caso de uso específico.

Ejemplo de ejecución

En las siguientes secciones, serializaré y deserializaré los mismos gráficos de objetos de Python usando diferentes serializadores. Para evitar la repetición, definiré estos gráficos de objetos aquí.

Gráfico de objetos simple

El gráfico de objetos simple es un diccionario que contiene una lista de números enteros, una cadena, un float, un booleano y un None.

Gráfico de objetos complejo

El gráfico de objetos complejo también es un diccionario, pero contiene un objeto datetime y una instancia de clase definida por el usuario que tiene un atributo self.simple, que se configura en el gráfico de objetos simple.

Pickle

Pickle es un elemento básico. Es un formato de serialización de objetos nativo de Python. La interfaz pickle proporciona cuatro métodos: dump, dumps, load, y loads. El método dump() se serializa en un archivo abierto (objeto similar a un archivo). El método dumps() se serializa en una cadena. El método load() se deserializa a partir de un objeto abierto similar a un archivo. El método loads() se deserializa a partir de una cadena.

Pickle admite de forma predeterminada un protocolo textual, pero también tiene un protocolo binario, que es más eficiente, pero no legible por humanos (útil al depurar).

Así es como se selecciona un gráfico de objeto de Python en una cadena y en un archivo usando ambos protocolos.

La representación binaria puede parecer más grande, pero esto es una ilusión debido a su presentación. Cuando se realiza un volcado en un archivo, el protocolo textual es de 130 bytes, mientras que el protocolo binario es de solo 85 bytes.

Descomprimir una cadena es tan simple como:

Ten en cuenta que pickle puede descubrir el protocolo automáticamente. No es necesario especificar un protocolo ni siquiera para el binario.

Descomprimir un archivo es igual de fácil. Solo necesitas proporcionar un archivo abierto.

Según la documentación, se supone que debes abrir pickles binarios usando el modo 'rb', pero como puedes ver, funciona de cualquier manera.

Veamos cómo pickle maneja el gráfico de objetos complejo.

La eficiencia del protocolo binario es aún mayor con gráficos de objetos complejos.

JSON

JSON (JavaScript Object Notation) forma parte de la biblioteca estándar de Python desde Python 2.5. Lo consideraré un formato nativo en este momento. Es un formato basado en texto y es el rey no oficial de la web en lo que respecta a la serialización de objetos. Su sistema de tipos presenta naturalmente JavaScript, por lo que es bastante limitado.

Serialicemos y deserialicemos los gráficos de objetos simples y complejos y veamos qué sucede. La interfaz es casi idéntica a la interfaz pickle. Tienes funciones dump(), dumps(), load() y loads(). Pero no hay protocolos para seleccionar y hay muchos argumentos opcionales para controlar el proceso. Comencemos de manera simple volcando el gráfico de objeto simple sin ningún argumento especial:

La salida se ve bastante legible, pero no hay indentación. Para un gráfico de objetos más grande, esto puede ser un problema. Indentemos la salida:

Se ve mucho mejor. Pasemos al gráfico de objetos complejo.

¡Wow! No se ve nada bien. ¿Qué pasó? El mensaje de error es que el objeto A no es serializable JSON. Recuerda que JSON tiene un sistema de tipos muy limitado y no puede serializar clases definidas por el usuario automáticamente. La forma de abordarlo es subclasificar la clase JSONEncoder utilizada por el módulo json e implementar el valor predeterminado default() que se llama cada vez que el codificador JSON se encuentra con un objeto que no puede serializar.

El trabajo del codificador personalizado es convertirlo en un gráfico de objeto Python que el codificador JSON pueda codificar. En este caso tenemos dos objetos que requieren una codificación especial: el objeto datetime y la clase A. El siguiente codificador hace el trabajo. Cada objeto especial se convierte en un dict donde la clave es el nombre del tipo rodeado de dunders (guiones bajos dobles). Esto será importante para la decodificación.

Intentemos de nuevo con nuestro codificador personalizado:

Esto es hermoso. El gráfico de objeto complejo se serializó correctamente y la información de tipo original de los componentes se conservó mediante las claves: "__A__" y "__datetime__". Si usas dunders para tus nombres, entonces debes idear una convención diferente para denotar tipos especiales.

Decodifiquemos el gráfico de objetos complejo.

Mmm, la deserialización funcionó (sin errores), pero es diferente al gráfico de objeto complejo original que serializamos. Algo anda mal. Veamos el gráfico de objetos deserializados. Usaré la función pprint del módulo pprint para una impresión bonita.

De acuerdo. El problema es que el módulo json no sabe nada sobre la clase A o incluso el objeto estándar de fecha y hora. Simplemente deserializa todo de forma predeterminada en el objeto Python que coincide con su sistema de tipos. Para volver a un gráfico de objetos de Python enriquecido, necesitas una decodificación personalizada.

No hay necesidad de una subclase de decodificadores personalizados. Las funciones load() y loads() proporcionan el parámetro "object_hook" que te permite proporcionar una función personalizada que convierte dicts en objetos.

Decodifiquemos usando la función decode_object() como un parámetro para el parámetro loads() object_hook.

Conclusión

En la primera parte de este tutorial, aprendiste sobre el concepto general de serialización y deserialización de objetos Python y exploraste las entradas y salidas de la serialización de objetos Python usando Pickle y JSON.

En la segunda parte, aprenderás sobre YAML, problemas de rendimiento y seguridad y una revisión rápida de esquemas de serialización adicionales.

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.