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 pickle except 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 pickle except ImportError: import pickle fichero = 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 pickle fichero = 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 pickle fichero = 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 animales2 print 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"] = lenguajes print shelf["segunda"] shelf.close()
Está bien el tuto si, yo he usado pickle alguna vez que otra con cosillas simples, pero no conocia el tercer parametro de dump jeje. De shelve si conocia su existencia, pero no me habia parado a leer que tenia de diferente con pickle.
Un saludo.
Mmm… Hablando de Python xD
Pondras «Python para todos» en Bubok?
Yo lo quiero comprar xD
Muchas gracias por tu aporte!
Realmente necesitaba un sitio así, con entradas detalladas sobre python cada cierto tiempo.
Sigue así!
genial pero fuera delos procesos y utilerias de python
alguien sabe como crear en si el programa en mac ???
con appletbuilder?
Muy bueno el artículo. En tu linea 🙂
Holas! Estoy leyendo tu libro tutorial que lo imprimí ayer. Esta muy bien y me está gustando mucho. Pero tengo una duda. Que IDE se puede utilizar para python? Sobre todo alguna que ayude mucho para el desarrollo de sitios web con Django.
He googleado algo y me he encontrado con OpenKomodo y con Stanis Python Editor. Tienen buena pinta pero ninguna trae soporte para proyectos de Django.
Gracias, Joaquín
Hola, puedes probar con eclipse (PyDev),
http://magpiebrain.com/blog/2006/10/09/using-eclipse-and-pydev-for-django/
Dejen de copiar del libro Python para todos …
Eso se llama Plagio!
Yo soy el autor de Python para todos, amigo. ¿Cómo me voy a plagiar a mí mismo? 😆
¿No te has fijado en la dirección web del libro? http://mundogeek.net/tutorial-python/ 😉
Pero gracias por defender mis intereses 🙂
dejenme libros de python donde se ha resumido
hola, soy miguel, programador ciego de argentina. estoy iniciandome con python, la verdad tengo que agradecerte por tu manual, muy claro. muchas gracias por tu tiempo dedicado!.
Que buen articulo.
Gracias.
Es un muy bien artículo les recomiendo me ayudo en mucho gracias. 🙂
Muito bom!!!
só deixo uma dica, para serializar imagens você vai precisar de algo como: http://stackoverflow.com/questions/10118068/pickleable-image-object
Hola que tal, soy nuevo en Python, tengo unos archivos .DAT generados en Python mediante un sistema, puedo visualizar parcialmente la informacion con btfiler, y por lo que he leido usaron tal vez shelve o pickle para crearlo, no tengo la estructura, hay forma de recuperar la informacion con shelve sin saber que objetos o estructura contienen los archivos? Muchas gracias.
Hola amigo que tal, intento implementar tu codigo pero me sale un error con «file» me dice que no es algo reconocido
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 animales2
print lenguajes2
Estuve probando esta parte (y en general todos los ejemplos) y cuando llego a esta parte pasa lo siguiente:
1) dice que «file» no se puede usar dado que no es algo conocido
2)dice que no puedo usar solo «w» ya que tiene que guardarse en bytes
3)siguiendo tu ejemplo al final cuando ejecutas el programa lo que te saldrá es: [«python», «mono», «perl»] [«python», «mono», «perl»] dado que al final el programa solo toma el último diccionario que guardaste que en este caso sería «lenguaje»