He creado un objeto como este:
company1.name = 'banana'
company1.value = 40
Me gustaría guardar este objeto. ¿Cómo puedo hacer eso?
protocol=pickle.HIGHEST_PROTOCOL
. Mi respuesta también da alternativas al pepinillo.
He creado un objeto como este:
company1.name = 'banana'
company1.value = 40
Me gustaría guardar este objeto. ¿Cómo puedo hacer eso?
protocol=pickle.HIGHEST_PROTOCOL
. Mi respuesta también da alternativas al pepinillo.
Respuestas:
Puede usar el pickle
módulo en la biblioteca estándar. Aquí hay una aplicación básica 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 definir su propia utilidad simple como la siguiente que abre un archivo y escribe un solo objeto en él:
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')
Dado que esta es una respuesta tan popular, me gustaría tocar algunos temas de uso ligeramente avanzados.
cPickle
(o _pickle
) vspickle
Casi siempre es preferible usar el cPickle
módulo en lugar de hacerlo 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, solo cambie la import
declaración a esto:
import cPickle as pickle
En Python 3, cPickle
se le cambió el nombre _pickle
, pero hacerlo ya no es necesario ya que el pickle
módulo ahora lo hace automáticamente. ¿Qué diferencia hay entre pickle y _pickle en python 3? .
El resumen es que podría usar algo como lo siguiente para asegurarse de que su código siempre use la versión C cuando esté disponible en Python 2 y 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
puede leer y escribir archivos en varios formatos diferentes, específicos de Python, llamados protocolos como se describe en la documentación , "Protocolo versión 0" es ASCII y por lo tanto "legible por humanos". Las versiones> 0 son binarias y la más alta disponible depende de la versión de Python que 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 del Protocolo 0
, pero en Python 3.8.1, es la versión del Protocolo 4
. En Python 3.x, el módulo tenía un pickle.DEFAULT_PROTOCOL
agregado, pero eso no existe en Python 2.
Afortunadamente, hay una forma abreviada de escribir pickle.HIGHEST_PROTOCOL
en cada llamada (suponiendo que eso es lo que desea, y generalmente lo hace), solo use el número literal -1
, similar a hacer referencia al último elemento de una secuencia a través de un índice negativo. Entonces, en lugar de escribir:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Solo puedes escribir:
pickle.dump(obj, output, -1)
De cualquier manera, solo habría especificado el protocolo una vez si hubiera creado un Pickler
objeto para usar en múltiples operaciones de encurtido:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Nota : Si se encuentra en un entorno que ejecuta diferentes versiones de Python, entonces probablemente quiera usar explícitamente (es decir, código rígido) un número de protocolo específico que todos puedan leer (las versiones posteriores generalmente pueden leer archivos producidos por versiones anteriores) .
Mientras que un archivo de salmuera puede contener cualquier número de objetos en escabeche, como se muestra en los ejemplos anteriores, cuando hay un número desconocido de ellos, a menudo es más fácil de almacenar todos ellos en algún tipo de recipiente de tamaño variable, como una list
, tuple
o dict
ya escribir todos ellos al 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 restaure 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 cargarlas de nuevo más tarde (aunque hacerlo sin esa información es posible, requiere un código ligeramente especializado). Ver las respuestas a la pregunta relacionada ¿ Guardar y cargar varios objetos en un archivo pickle? para obtener detalles sobre las diferentes formas de hacer esto. Personalmente, me gusta la respuesta de @Lutz Prechelt . 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))
company1
y company2
. ¿Por qué no eliminas Company
y muestras lo que sucede también?
Creo que es una suposición bastante fuerte suponer que el objeto es a class
. ¿Qué pasa si no es un 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 de Python tienen atributos agregados a su __dict__
creación posterior, pickle
no respeta la adición de esos atributos (es decir, 'olvida' que se agregaron, porque pickle
serializa por referencia a la definición del objeto).
En todos estos casos, pickle
y cPickle
puede fallar horriblemente.
Si está buscando guardar un object
(creado arbitrariamente), donde tiene atributos (ya sea agregados 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 puedo manejarlo. Try de Let dill
. Agregaremos otro tipo de objeto (a 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 pickle
falla, y dill
no lo hace, es que se dill
trata __main__
como un módulo (en su mayor parte), y también puede encurtir definiciones de clase en lugar de encurtir por referencia (como lo pickle
hace). La razón por la que se dill
puede lambda
encurtir es porque le da un nombre ... entonces puede ocurrir la magia de encurtido.
En realidad, hay una manera más fácil de guardar todos estos objetos, especialmente si tiene muchos objetos que ha creado. Simplemente descargue toda la sesión 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, disfrute de un espresso o lo que sea, y regrese 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 inconveniente importante es que dill
no forma 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 lo último dill
con git+https://github.com/uqfoundation/dill.git@master#egg=dill
. Y puede obtener la última versión lanzada con pip install dill
.
TypeError: __new__() takes at least 2 arguments (1 given)
cuando intento usar dill
(que parece prometedor) con un objeto bastante complejo que incluye un archivo de audio.
TypeError
cuando haces qué, exactamente? Eso suele ser una señal de tener un número incorrecto de argumentos al crear instancias de una instancia de clase. Si esto no es parte del flujo de trabajo de la pregunta anterior, ¿podría publicarlo como otra pregunta, dill
enviármelo por correo electrónico o agregarlo como un problema en la página de Github?
dill
problema.
dil
¡ MemoryError
Aunque me da ! también lo hace cPickle
, pickle
y hickle
.
Puede usar cualquier caché para hacer el trabajo por usted. Considera todos los detalles:
pickle
módulo de Python para manejar lambda
y todas las características agradables de Python.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 myfunc
por primera vez y selecciona el resultado en un archivo cachedir
utilizando un identificador único (dependiendo del nombre de la función y sus argumentos) como nombre de archivo. En cualquier ejecución consecutiva, se carga el objeto encurtido. Si cachedir
se conserva entre las ejecuciones de Python, el objeto encurtido se toma de la ejecución anterior de Python.
Para más detalles ver la documentación
anycache
para guardar más de una instancia de, digamos, un class
contenedor como un list
(que no fue el resultado de llamar a una función)?
Ejemplo rápido usando company1
de su pregunta, con python3.
import pickle
# Save the file
pickle.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = pickle.load(open("company1.pickle", "rb"))
Sin embargo, como señaló esta respuesta , el pepinillo a menudo falla. Así que realmente deberías usarlo dill
.
import dill
# Save the file
dill.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = dill.load(open("company1.pickle", "rb"))