Python: Serialización de Objetos

Algunas veces tenemos la necesidad de guardar un objeto a disco para poder recuperarlo más tarde, o puede que nos sea necesario mandar un objeto a través de la red, a otro programa en Python ejecutándose en otra máquina.

Al proceso de transformar el estado de un objeto en un formato que se pueda almacenar, recuperar y transportar se le conoce con el nombre de serialización o marshalling.

En Python tenemos varios módulos que nos facilitan esta tarea, como marshal, pickle, cPickle y shelve.

El módulo marshal es el más básico y el más primitivo de los tres, y es que, de hecho, su propósito principal y su razón de ser no es el de serializar objetos, sino trabajar con bytecode Python (archivos .pyc).

marshal sólo permite serializar objetos simples (la mayoría de los tipos incluidos por defecto en Python), y no proporciona ningún tipo de mecanismo de seguridad ni comprobaciones frente a datos corruptos o mal formateados. Es más, el formato utilizado para guardar el bytecode (y por tanto el formato utilizado para guardar los objetos con marshal) puede cambiar entre versiones, por lo que no es adecuado para almacenar datos de larga duración.

pickle, por su parte, permite serializar casi cualquier objeto (objetos de tipos definidos por el usuario, colecciones que contienen colecciones, etc) y cuenta con algunos mecanismos de seguridad básicos. Sin embargo, al ser más complejo que marshal, y, sobre todo, al estar escrito en Python en lugar de en C, como marshal, también es mucho más lento.

La solución, si la velocidad de la serialización es importante para nuestra aplicación, es utilizar cPickle, que no es más que es una implementación en C de pickle. cPickle es hasta 1000 veces más rápido que pickle, y prácticamente igual de rápido que marshal.

Si intentamos importar cPickle y se produce un error por algún motivo, se lanzará una excepción de tipo ImportError. Para utilizar cPickle si está disponible y pickle en caso contrario, podríamos usar un código similar al siguiente:

try:
import cPickle as pickleexcept
ImportError: import pickle

as en un import sirve para importar el elemento seleccionado utilizando otro nombre indicado, en lugar de su nombre.

La forma más sencilla de serializar un objeto usando pickle es mediante una llamada a la función dump pasando como argumento el nombre del objeto a serializar y un objeto archivo en el que guardarlo (o cualquier otro tipo de objeto similar a un archivo, siempre que ofrezca métodos read, realine y write).

try:
import cPickle as pickleexcept
ImportError:
import pick
lefichero = file("datos.dat", "w")
animales = ["piton", "mono", "camello"]
pickle.dump(animales, fichero)
fichero.close()

La función dump también tiene un parámetro opcional protocol que indica el protocolo a utilizar al guardar. Por defecto su valor es 0, que utiliza formato texto y es el menos eficiente. El protocolo 1 es más eficiente que el 0, pero menos que el 2. Tanto el protocolo 1 como el 2 utilizan un formato binario para guardar los datos.

try:
import cPickle as pickle
except ImportError:
import picklefichero = file("datos.dat", "w")
animales = ["piton", "mono", "camello"]
pickle.dump(animales, fichero, 2)
fichero.close()

Para volver a cargar un objeto serializado se utiliza la función load, a la que se le pasa el archivo en el que se guardó.

try:
import cPickle as pickle
except ImportError:
import picklefichero = file("datos.dat", "w")
animales = ["piton", "mono", "camello"]
pickle.dump(animales, fichero)
fichero.close()fichero = file("datos.dat")
animales2 = pickle.load(fichero)
print animales2

Supongamos ahora que queremos almacenar un par de listas en un fichero. Esto sería tan sencillo como llamar una vez a dump por cada lista, y llamar después una vez a load por cada lista.

fichero = file("datos.dat", "w")
animales = ["piton", "mono", "camello"]
lenguajes = ["python", "mono", "perl"]
pickle.dump(animales, fichero)
pickle.dump(lenguajes, fichero)
fichero = file("datos.dat")
animales2 = pickle.load(fichero)
lenguajes2 = pickle.load(fichero)
print animales2print lenguajes2

Pero, ¿y si hubiéramos guardado 30 objetos y quisiéramos acceder al último de ellos? ¿o si no recordáramos en qué posición lo habíamos guardado? El módulo shelve extiende pickle / cPickle para proporcionar una forma de realizar la serialización más clara y sencilla, en la que podemos acceder a la versión serializada de un objeto mediante una cadena asociada, a través de una estructura parecida a un diccionario.

La única función que necesitamos conocer del módulo shelve es open, que cuenta con un parámetro filename mediante el que indicar la ruta a un archivo en el que guardar los objetos (en realidad se puede crear más de un archivo, con nombres basados en filename, pero esto es transparente al usuario).

La función open también cuenta con un parámetro opcional protocol, con el que especificar el protocolo que queremos que utilice pickle por debajo.

Como resultado de la llamada a open obtenemos un objeto Shelf, con el que podemos trabajar como si de un diccionario normal se tratase (a excepción de que las claves sólo pueden ser cadenas) para almacenar y recuperar nuestros objetos.

Como un diccionaro cualquiera la clase Shelf cuenta con métodos get, has_key, items, keys, values, …

Una vez hemos terminado de trabajar con el objeto Shelf, lo cerramos usando el método close.

import shelve
animales = ["piton", "mono", "camello"]
lenguajes = ["python", "mono", "perl"]
shelf = shelve.open("datos.dat")
shelf["primera"] = animales
shelf["segunda"] = lenguajesprint
shelf["segunda"]shelf.close()

Particularmente, utilizo mucho este módulo de pickle cuando tengo que trasladar objetos desde un servidor de producción a un servidor de desarrollo y viceversa, lo cual resulta muy útil.

efWLSFUJWjpZzNJdW

comment4, drugs, drugs, drugstore, pharmacy,

bNfhwkMTypeXx

CYXhIJIgeDtEgcFqsog

vJqWNJkBxJWdMhE

XyJUuVfwObwuEHQOdQO

NSgEbhDvXtglbp

HBQOkTrupYEjUP

comment4, recipe, this, this, this, hosting, link, links,

daHJCWiFQjs

comment3, links, table, sites, this, link, hosting, link, links,

HWIAZJLZLtYWl

comment1,

VOHerLsQohiDv

xVRDqGpMLybIaKVbQfH

NhHdbyMQXDTqocqNV

QrcUExnuaQCkuegJI

VLWUDLrhojpGZZG

iuTAEVlhbk

QzPGeNbusMdr

iLYoImDLheePmOx

qRIxVszEzvVaNy

DGxWCJEuVlNpF

vhgPSqMdNojKwgzNTSD

jVAIFtFPlVNfGgYHLX

jNPqNRLxnOpWG

IxnyEeqDur

zekAHllkZZ

KwwQfHOIJROdRxaT

jMueHbqAadf

NNjDCqGjceMyGLQjl

CzwIIoYvwvoOiKK

BwXwibGQxP

vXqprRDDlaMJkn

bhESuqAqhoOpzq

HnYifYIsOUPEGwYLu

lvqsGDccTKZGPqonlz