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 cPicklemódulo en lugar de hacerlo pickleporque 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 importdeclaración a esto:
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 pickleexceptModuleNotFoundError:import pickle
Formatos de flujo de datos (protocolos)
picklepuede 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_PROTOCOLagregado, pero eso no existe en Python 2.
Afortunadamente, hay una forma abreviada de escribir pickle.HIGHEST_PROTOCOLen 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 Picklerobjeto para usar en múltiples operaciones de encurtido:
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) .
Objetos múltiples
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, tupleo dictya escribir todos ellos al archivo en una sola llamada:
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í:
classCompany:def __init__(self, name, value):
self.name = name
self.value = valuedef pickled_items(filename):""" Unpickle a file of pickled data. """with open(filename,"rb")as f:whileTrue:try:yield pickle.load(f)exceptEOFError:breakprint('Companies in pickle file:')for company in pickled_items('company_data.pkl'):print(' name: {}, value: {}'.format(company.name, company.value))
Esto es raro para mí porque imaginé que habría una manera más fácil de guardar un objeto ... Algo como 'saveobject (empresa1, c: \ mypythonobjects)
Peterstone
44
@Peterstone: si solo quisiera almacenar un objeto, solo necesitaría la mitad de la cantidad de código que en mi ejemplo; lo escribí a propósito como lo hice para mostrar cómo se puede guardar más de un objeto (y luego volver a leerlo de) el mismo archivo.
Martineau
1
@Peterstone, hay una muy buena razón para la separación de responsabilidades. De esta manera, no hay limitación sobre cómo se utilizan los datos del proceso de decapado. Puede almacenarlo en un disco o también puede enviarlo a través de una conexión de red.
Harald Scheirich
3
@martinaeau, esto fue en respuesta a la observación de perstones sobre que uno debería tener una sola función para guardar un objeto en el disco. La responsabilidad de los encurtidos es solo convertir un objeto en datos que puedan manejarse como un fragmento. Escribir cosas en el archivo es responsabilidad de los objetos del archivo. Al mantener las cosas separadas, se permite una mayor reutilización, por ejemplo, poder enviar los datos encurtidos a través de una conexión de red o almacenarlos en una base de datos, todas las responsabilidades se separan de la conversión real de datos <-> objeto
Harald Scheirich
1
Eliminas company1y company2. ¿Por qué no eliminas Companyy muestras lo que sucede también?
Mike McKerns
49
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, pickleno respeta la adición de esos atributos (es decir, 'olvida' que se agregaron, porque pickleserializa por referencia a la definición del objeto).
En todos estos casos, pickley cPicklepuede 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 ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import pickle>>>classCompany:...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 ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"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 loadreturnUnpickler(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 ... pickleno puedo manejarlo. Try de Let dill. Agregaremos otro tipo de objeto (a lambda) por si acaso.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"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.value40>>> company2.name'rhubarb'>>> company2.value42>>>
Funciona. La razón picklefalla, y dillno lo hace, es que se dilltrata __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 picklehace). La razón por la que se dillpuede lambdaencurtir 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.
Ahora apague su computadora, disfrute de un espresso o lo que sea, y regrese más tarde ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import dill>>> dill.load_session('dill.pkl')>>> company1.name'banana'>>> company1.value40>>> company2.name'rhubarb'>>> company2.value42>>> company2<function <lambda> at 0x1065f2938>
El único inconveniente importante es que dillno 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 dillcon git+https://github.com/uqfoundation/dill.git@master#egg=dill. Y puede obtener la última versión lanzada con pip install dill.
Recibo un mensaje 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.
MikeiLL
1
@MikeiLL: ¿Recibes un TypeErrorcuando 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, dillenviármelo por correo electrónico o agregarlo como un problema en la página de Github?
Mike McKerns
3
Para cualquiera que lo siga, esta es la pregunta relacionada que @MikeLL publicó: a partir de la respuesta, aparentemente no fue un dillproblema.
Martineau 02 de
dil¡ MemoryErrorAunque me da ! también lo hace cPickle, pickley hickle.
Färid Alijani
4
Puede usar cualquier caché para hacer el trabajo por usted. Considera todos los detalles:
Utiliza eneldo como backend, que extiende el picklemódulo de Python para manejar lambday todas las características agradables de Python.
Almacena diferentes objetos en diferentes archivos y los vuelve a cargar correctamente.
Limita el tamaño de 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 myfuncque crea la instancia:
from anycache import anycacheclassCompany(object):def __init__(self, name, value):
self.name = name
self.value = value@anycache(cachedir='/path/to/your/cache')def myfunc(name, value)returnCompany(name, value)
Anycache llama myfuncpor primera vez y selecciona el resultado en un archivo cachedirutilizando 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 cachedirse conserva entre las ejecuciones de Python, el objeto encurtido se toma de la ejecución anterior de Python.
¿Cómo se usaría anycachepara guardar más de una instancia de, digamos, un classcontenedor como un list(que no fue el resultado de llamar a una función)?
Martineau
2
Ejemplo rápido usando company1de 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"))
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:También puede definir su propia utilidad simple como la siguiente que abre un archivo y escribe un solo objeto en él:
Actualizar
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 hacerlopickle
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 laimport
declaración a esto:En Python 3,
cPickle
se le cambió el nombre_pickle
, pero hacerlo ya no es necesario ya que elpickle
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:
Formatos de flujo de datos (protocolos)
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 Protocolo0
, pero en Python 3.8.1, es la versión del Protocolo4
. En Python 3.x, el módulo tenía unpickle.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:Solo puedes escribir:
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: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) .
Objetos múltiples
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
odict
ya escribir todos ellos al archivo en una sola llamada:y restaure la lista y todo en ella más tarde con:
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í:
fuente
company1
ycompany2
. ¿Por qué no eliminasCompany
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 unclass
? 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, porquepickle
serializa por referencia a la definición del objeto).En todos estos casos,
pickle
ycPickle
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 usardill
, que puede serializar casi cualquier cosa en Python.Comenzamos con una clase ...
Ahora apague y reinicie ...
Vaya ...
pickle
no puedo manejarlo. Try de Letdill
. Agregaremos otro tipo de objeto (alambda
) por si acaso.Y ahora lee el archivo.
Funciona. La razón
pickle
falla, ydill
no lo hace, es que sedill
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 lopickle
hace). La razón por la que sedill
puedelambda
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.
Ahora apague su computadora, disfrute de un espresso o lo que sea, y regrese más tarde ...
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
congit+https://github.com/uqfoundation/dill.git@master#egg=dill
. Y puede obtener la última versión lanzada conpip install dill
.fuente
TypeError: __new__() takes at least 2 arguments (1 given)
cuando intento usardill
(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 hacecPickle
,pickle
yhickle
.Puede usar cualquier caché para hacer el trabajo por usted. Considera todos los detalles:
pickle
módulo de Python para manejarlambda
y todas las características agradables de Python.Suponiendo que tiene una función
myfunc
que crea la instancia:Anycache llama
myfunc
por primera vez y selecciona el resultado en un archivocachedir
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. Sicachedir
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
fuente
anycache
para guardar más de una instancia de, digamos, unclass
contenedor como unlist
(que no fue el resultado de llamar a una función)?Ejemplo rápido usando
company1
de su pregunta, con python3.Sin embargo, como señaló esta respuesta , el pepinillo a menudo falla. Así que realmente deberías usarlo
dill
.fuente