¿Cómo guardo y restauro múltiples variables en Python?

105

Necesito guardar alrededor de una docena de objetos en un archivo y luego restaurarlos. Intenté usar un bucle for con pickle y shelve pero no funcionó bien.

Editar.
Todos los objetos que estaba tratando de guardar estaban en la misma clase (debería haber mencionado esto antes), y no me di cuenta de que podía guardar toda la clase así:

import pickle
def saveLoad(opt):
    global calc
    if opt == "save":
        f = file(filename, 'wb')
        pickle.dump(calc, f, 2)
        f.close
        print 'data saved'
    elif opt == "load":
        f = file(filename, 'rb')
        calc = pickle.load(f)
    else:
        print 'Invalid saveLoad option'
fuego lunar
fuente
1
Dices que has probado un bucle for. Por favor publique ese código y por qué "no funcionó bien" (es decir, qué sucedió y qué quería que sucediera).
Blair
Si está en Windows, asegúrese de abrir los archivos en modo binario
John La Rooy
@gnibbler: el modo binario solo es necesario para los protocolos no predeterminados ( docs.python.org/library/pickle.html#usage ).
Eric O Lebigot

Respuestas:

170

Si necesita guardar varios objetos, simplemente puede ponerlos en una sola lista o tupla, por ejemplo:

import pickle

# obj0, obj1, obj2 are created here...

# Saving the objects:
with open('objs.pkl', 'w') as f:  # Python 3: open(..., 'wb')
    pickle.dump([obj0, obj1, obj2], f)

# Getting back the objects:
with open('objs.pkl') as f:  # Python 3: open(..., 'rb')
    obj0, obj1, obj2 = pickle.load(f)

Si tiene muchos datos, puede reducir el tamaño del archivo pasando protocol=-1a dump(); pickleentonces utilizará el mejor protocolo disponible en lugar del protocolo histórico predeterminado (y más compatible con versiones anteriores). En este caso, el archivo debe abrirse en modo binario ( wby rb, respectivamente).

El modo binario también debe usarse con Python 3, ya que su protocolo predeterminado produce datos binarios (es decir, que no son de texto) (modo de escritura 'wb'y modo de lectura 'rb').

Eric O Lebigot
fuente
12
En Python 3.5, tuve que abrir el archivo en modo "byte", por ejemplo with open('objs.pickle', 'wb') as f:(observe el wb).
kbrose
Hola @Eric, ¿cuál es la necesidad de with open('objs.pkl') as f:comparar simplemente obj1, obj2 = pickle.load(open("objs.pkl","rb"))? ¿Hay alguna diferencia entre estos dos?
balandongiv
Con el segundo formulario no cierra el archivo. Esto no se considera una buena práctica, ya que la cantidad de archivos que se pueden abrir en paralelo suele estar bastante limitada por los sistemas operativos (¡pruebe con un bucle que abra archivos sin cerrarlos!). Dicho esto, en la práctica, no cerrar el archivo a menudo funciona cuando no abres muchos archivos.
Eric O Lebigot
51

Hay una biblioteca incorporada llamada pickle. Usando picklepuede volcar objetos a un archivo y cargarlos más tarde.

import pickle

f = open('store.pckl', 'wb')
pickle.dump(obj, f)
f.close()

f = open('store.pckl', 'rb')
obj = pickle.load(f)
f.close()
Yossi
fuente
1
Yo uso Python 3.4: f = open('store.pckl', 'wb')para abrir un archivo para escribir. Consulte stackoverflow.com/questions/13906623/… Y use `f = open ('store.pckl', 'rb') para abrir un archivo para leer. Consulte stackoverflow.com/questions/7031699/… .
user3731622
¿Es esto específico de 3.4+? Casi rechazo la respuesta porque genera errores cuando no usa 'b'.
Wilmer E. Henao
12

Debería mirar los módulos de estantería y encurtidos . Si necesita almacenar muchos datos, puede ser mejor usar una base de datos

John La Rooy
fuente
Quiero guardar un solo objeto que inicia sesión en un servidor en la nube, para poder manejar si inicio sesión varias veces a lo largo del tiempo, el servidor rechaza mi solicitud. ¿El volcado de un objeto en un archivo usando el módulo pickle puede tener algún problema de seguridad? , por ejemplo, si alguien obtiene mi objeto descargado, puede iniciar sesión en mi almacenamiento en la nube sin usar una contraseña.
alper
5

Otro enfoque para guardar múltiples variables en un archivo pickle es:

import pickle

a = 3; b = [11,223,435];
pickle.dump([a,b], open("trial.p", "wb"))

c,d = pickle.load(open("trial.p","rb"))

print(c,d) ## To verify
Guruprasad Raghavan
fuente
4

Puede usar klepto, que proporciona almacenamiento en caché persistente en la memoria, el disco o la base de datos.

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[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.
>>> from klepto.archives import file_archive
>>> db = file_archive('foo.txt')
>>> db['1'] = 1
>>> db['max'] = max
>>> squared = lambda x: x**2
>>> db['squared'] = squared
>>> def add(x,y):
...   return x+y
... 
>>> db['add'] = add
>>> class Foo(object):
...   y = 1
...   def bar(self, x):
...     return self.y + x
... 
>>> db['Foo'] = Foo
>>> f = Foo()
>>> db['f'] = f  
>>> db.dump()
>>> 

Luego, después de reiniciar el intérprete ...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[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.
>>> from klepto.archives import file_archive
>>> db = file_archive('foo.txt')
>>> db
file_archive('foo.txt', {}, cached=True)
>>> db.load()
>>> db
file_archive('foo.txt', {'1': 1, 'add': <function add at 0x10610a0c8>, 'f': <__main__.Foo object at 0x10510ced0>, 'max': <built-in function max>, 'Foo': <class '__main__.Foo'>, 'squared': <function <lambda> at 0x10610a1b8>}, cached=True)
>>> db['add'](2,3)
5
>>> db['squared'](3)
9
>>> db['f'].bar(4)
5
>>> 

Obtenga el código aquí: https://github.com/uqfoundation

Mike McKerns
fuente
7
El OP no solicitó el integrado.
Mike McKerns
4

El siguiente enfoque parece simple y se puede utilizar con variables de diferente tamaño:

import hickle as hkl
# write variables to filename [a,b,c can be of any size]
hkl.dump([a,b,c], filename)

# load variables from filename
a,b,c = hkl.load(filename)
diablo en el detalle
fuente
hickleEl paquete es más robusto (menos propenso a errores) e incluso más simple (menos código) que pickle.
user2340939