how custom create python object save pickle

python - custom - Guardar un objeto(persistencia de datos)



pickle save text (3)

Creé un objeto como este:

company1.name = ''banana'' company1.value = 40

Me gustaría guardar este objeto ¿Cómo puedo hacer eso?


Creo que es una suposición bastante fuerte suponer que el objeto es una class . ¿Qué pasa si no es una class ? También existe la suposición de que el objeto no estaba definido en el intérprete. ¿Qué pasa si se definió en el intérprete? Además, ¿qué pasa si los atributos se agregaron dinámicamente? Cuando algunos objetos Python tienen atributos agregados a su __dict__ después de la creación, pickle no respeta la adición de esos atributos (es decir, ''olvida'' que fueron agregados, porque pickle serializa por referencia a la definición del objeto).

En todos estos casos, pickle y cPickle pueden fallar horriblemente.

Si está buscando guardar un object (creado arbitrariamente), donde tiene atributos (ya sea añadidos en la definición del objeto o después) ... su mejor opción es usar dill , que puede serializar casi cualquier cosa en python.

Comenzamos con una clase ...

Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import pickle >>> class Company: ... pass ... >>> company1 = Company() >>> company1.name = ''banana'' >>> company1.value = 40 >>> with open(''company.pkl'', ''wb'') as f: ... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL) ... >>>

Ahora apague y reinicie ...

Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import pickle >>> with open(''company.pkl'', ''rb'') as f: ... company1 = pickle.load(f) ... Traceback (most recent call last): File "<stdin>", line 2, in <module> File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378, in load return Unpickler(file).load() File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load dispatch[key](self) File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090, in load_global klass = self.find_class(module, name) File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126, in find_class klass = getattr(mod, name) AttributeError: ''module'' object has no attribute ''Company'' >>>

Vaya ... pickle no puede manejarlo. Probemos dill . Lanzaremos otro tipo de objeto (una lambda ) por si acaso.

Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import dill >>> class Company: ... pass ... >>> company1 = Company() >>> company1.name = ''banana'' >>> company1.value = 40 >>> >>> company2 = lambda x:x >>> company2.name = ''rhubarb'' >>> company2.value = 42 >>> >>> with open(''company_dill.pkl'', ''wb'') as f: ... dill.dump(company1, f) ... dill.dump(company2, f) ... >>>

Y ahora lee el archivo.

Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import dill >>> with open(''company_dill.pkl'', ''rb'') as f: ... company1 = dill.load(f) ... company2 = dill.load(f) ... >>> company1 <__main__.Company instance at 0x107909128> >>> company1.name ''banana'' >>> company1.value 40 >>> company2.name ''rhubarb'' >>> company2.value 42 >>>

Funciona. La razón por la cual el pickle falla, y el dill no, es que el dill trata __main__ como un módulo (en su mayor parte), y también puede eliminar las definiciones de clase en lugar del decapado por referencia (como pickle ). La razón por la cual el dill puede encurtir una lambda es porque le da un nombre ... entonces la magia de decapado puede suceder.

En realidad, hay una manera más fácil de guardar todos estos objetos, especialmente si tiene muchos objetos que ha creado. Simplemente descargue la sesión completa de Python y vuelva a ella más tarde.

Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import dill >>> class Company: ... pass ... >>> company1 = Company() >>> company1.name = ''banana'' >>> company1.value = 40 >>> >>> company2 = lambda x:x >>> company2.name = ''rhubarb'' >>> company2.value = 42 >>> >>> dill.dump_session(''dill.pkl'') >>>

Ahora apague su computadora, vaya a disfrutar de un espresso o lo que sea, y vuelva más tarde ...

Python 2.7.8 (default, Jul 13 2014, 02:29:54) [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import dill >>> dill.load_session(''dill.pkl'') >>> company1.name ''banana'' >>> company1.value 40 >>> company2.name ''rhubarb'' >>> company2.value 42 >>> company2 <function <lambda> at 0x1065f2938>

El único gran inconveniente es que el dill no es parte de la biblioteca estándar de Python. Entonces, si no puede instalar un paquete de Python en su servidor, entonces no puede usarlo.

Sin embargo, si puede instalar paquetes de Python en su sistema, puede obtener el dill más reciente con git+https://github.com/uqfoundation/dill.git@master#egg=dill . Y puede obtener la última versión lanzada con pip install dill .


Puede usar anycache para hacer el trabajo por usted. Considera todos los detalles:

  • Utiliza dill como backend, que extiende el módulo de pickle para manejar lambda y todas las bonitas características de python.
  • Almacena diferentes objetos en diferentes archivos y los vuelve a cargar correctamente.
  • Limita el tamaño de la caché
  • Permite borrar el caché
  • Permite compartir objetos entre múltiples ejecuciones
  • Permite el respeto de los archivos de entrada que influyen en el resultado

Suponiendo que tiene una función myfunc que crea la instancia:

from anycache import anycache class Company(object): def __init__(self, name, value): self.name = name self.value = value @anycache(cachedir=''/path/to/your/cache'') def myfunc(name, value) return Company(name, value)

Anycache llama a myfunc por primera vez y guarda el resultado en un archivo en cachedir usando un identificador único (dependiendo del nombre de la función y sus argumentos) como nombre de archivo. En cualquier ejecución consecutiva, el objeto escabechado se carga. Si el cachedir se conserva entre ejecuciones python, el objeto escabechado se toma de la ejecución anterior de python.

Para más detalles, consulte la documentación


Puede usar el módulo pickle en la biblioteca estándar. Aquí hay una aplicación elemental de este para su ejemplo:

import pickle class Company(object): def __init__(self, name, value): self.name = name self.value = value with open(''company_data.pkl'', ''wb'') as output: company1 = Company(''banana'', 40) pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL) company2 = Company(''spam'', 42) pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL) del company1 del company2 with open(''company_data.pkl'', ''rb'') as input: company1 = pickle.load(input) print(company1.name) # -> banana print(company1.value) # -> 40 company2 = pickle.load(input) print(company2.name) # -> spam print(company2.value) # -> 42

También puede escribir una utilidad simple como la siguiente que abre un archivo y le escribe un único objeto:

def save_object(obj, filename): with open(filename, ''wb'') as output: # Overwrites any existing file. pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL) # sample usage save_object(company1, ''company1.pkl'')

Actualizar:

Dado que esta es una respuesta tan popular, me gustaría tocar algunos temas de uso ligeramente avanzados.

cPickle vs pickle

Casi siempre es preferible utilizar el módulo cPickle lugar de pickle porque el primero está escrito en C y es mucho más rápido. Hay algunas diferencias sutiles entre ellos, pero en la mayoría de las situaciones son equivalentes y la versión C proporcionará un rendimiento muy superior. Cambiar a él no podría ser más fácil, simplemente cambie la declaración de import a esto:

import cPickle as pickle

En Python 3, cPickle se renombró _pickle , pero hacer esto ya no es necesario, ya que el módulo pickle ahora lo hace de forma automática: ¿qué diferencia hay entre pickle y _pickle en python 3? .

Formatos de flujo de datos (protocolos)

pickle puede leer y escribir archivos en varios formatos diferentes, específicos de Python, llamados protocolos . La "versión de protocolo 0" es ASCII y, por lo tanto, "legible por humanos". Las versiones> 1 son binarias y la más alta disponible depende de qué versión de Python se esté utilizando. El valor predeterminado también depende de la versión de Python. En Python 2, el valor predeterminado era la versión de protocolo 0 , pero en Python 3.6 es la versión de protocolo 3 . En Python 3.x el módulo tenía un pickle.DEFAULT_PROTOCOL agregado a él, pero eso no existe en Python 2.

Afortunadamente hay una forma abreviada de escribir pickle.HIGHEST_PROTOCOL en cada llamada (asumiendo que es lo que quieres, y usualmente lo haces) -solo usa el número literal -1 . Entonces, en lugar de escribir:

pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)

Puedes escribir:

pickle.dump(obj, output, -1)

De cualquier manera, solo habría especificado el protocolo una vez si creó un objeto Pickler para usar en operaciones de pickle múltiples:

pickler = pickle.Pickler(output, -1) pickler.dump(obj1) pickler.dump(obj2) etc...

Múltiples objetos

Mientras que un archivo de pickle puede contener cualquier cantidad de objetos encurtidos, como se muestra en las muestras anteriores, cuando hay un número desconocido de ellos, a menudo es más fácil almacenarlos en un contenedor de tamaño variable, como una list , tuple o dict y escribirlos todos en el archivo en una sola llamada:

tech_companies = [ Company(''Apple'', 114.18), Company(''Google'', 908.60), Company(''Microsoft'', 69.18) ] save_object(tech_companies, ''tech_companies.pkl'')

y restaurar la lista y todo en ella más tarde con:

with open(''tech_companies.pkl'', ''rb'') as input: tech_companies = pickle.load(input)

La principal ventaja es que no necesita saber cuántas instancias de objetos se guardan para volver a cargarlas más tarde (aunque hacerlo sin esa información es posible, requiere algún código ligeramente especializado). Consulte las respuestas a la pregunta relacionada ¿Cómo guardar y cargar varios objetos en el archivo de pickle? para detalles sobre diferentes maneras de hacer esto. Personalmente, me gusta la answer @Lutz Prechelt de la mejor manera. Aquí está adaptado a los ejemplos aquí:

class Company: def __init__(self, name, value): self.name = name self.value = value def pickled_items(filename): """ Unpickle a file of pickled data. """ with open(filename, "rb") as f: while True: try: yield pickle.load(f) except EOFError: break print(''Companies in pickle file:'') for company in pickled_items(''company_data.pkl''): print('' name: {}, value: {}''.format(company.name, company.value))