Como faço para salvar e restaurar várias variáveis ​​em python?

105

Preciso salvar cerca de uma dúzia de objetos em um arquivo e restaurá-los mais tarde. Tentei usar um loop for com pickle e shelve, mas não funcionou direito.

Editar.
Todos os objetos que eu estava tentando salvar estavam na mesma classe (eu deveria ter mencionado isso antes), e eu não percebi que poderia salvar a classe inteira assim:

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'
lunarfyre
fonte
1
Você diz que tentou um loop for. Publique esse código e por que "não funcionou direito" (ou seja, o que aconteceu e o que você queria que acontecesse).
Blair
Se você estiver no Windows, certifique-se de abrir os arquivos no modo binário
John La Rooy
@gnibbler: o modo binário só é necessário para os protocolos não padrão ( docs.python.org/library/pickle.html#usage ).
Eric O Lebigot

Respostas:

170

Se você precisar salvar vários objetos, pode simplesmente colocá-los em uma única lista, ou tupla, por exemplo:

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)

Se você tiver muitos dados, pode reduzir o tamanho do arquivo passando protocol=-1para dump(); pickleirá então usar o melhor protocolo disponível em vez do protocolo histórico padrão (e mais compatível com versões anteriores). Neste caso, o arquivo deve ser aberto no modo binário ( wbe rb, respectivamente).

O modo binário também deve ser usado com Python 3, pois seu protocolo padrão produz dados binários (ou seja, não texto) (modo de escrita 'wb'e modo de leitura 'rb').

Eric O Lebigot
fonte
12
No Python 3.5, tive que abrir o arquivo no modo "byte", por exemplo with open('objs.pickle', 'wb') as f:(observe o wb).
kbrose
Olá @Eric, qual é a necessidade de with open('objs.pkl') as f:comparar com simplesmente obj1, obj2 = pickle.load(open("objs.pkl","rb"))? Existe alguma diferença entre esses dois?
balandongiv
Com o segundo formulário você não fecha o arquivo. Isso não é considerado uma boa prática, pois o número de arquivos que você pode abrir em paralelo geralmente é bastante limitado pelos sistemas operacionais (tente um loop que abre arquivos sem fechá-los!). Dito isso, na prática, não fechar o arquivo geralmente funciona, quando você não abre muitos arquivos.
Eric O Lebigot
51

Existe uma biblioteca interna chamada pickle. Usando picklevocê pode despejar objetos em um arquivo e carregá-los mais 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
fonte
1
I Python 3.4 uso: f = open('store.pckl', 'wb')para abrir um arquivo para escrever. Consulte stackoverflow.com/questions/13906623/… E use `f = open ('store.pckl', 'rb') para abrir um arquivo para leitura. Consulte stackoverflow.com/questions/7031699/… .
user3731622
isso é específico para 3.4+? Quase votei contra a resposta porque gera erros quando você não usa 'b'.
Wilmer E. Henao
12

Você deve olhar para os módulos de prateleira e picles . Se você precisa armazenar muitos dados, pode ser melhor usar um banco de dados

John La Rooy
fonte
Quero salvar um único objeto que efetua login em um servidor em nuvem, para que, se eu efetuar login várias vezes ao longo do tempo, o servidor rejeitar minha solicitação. Despejar um objeto em um arquivo usando o módulo pickle pode ter algum problema de segurança? , por exemplo, onde se alguém obtiver meu objeto despejado, poderá fazer o login no meu armazenamento em nuvem sem usar uma senha.
Alper
5

Outra abordagem para salvar várias variáveis ​​em um arquivo pickle é:

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
fonte
4

Você pode usar o klepto, que fornece armazenamento em cache persistente na memória, disco ou banco de dados.

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()
>>> 

Então, após reiniciar o 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
>>> 

Obtenha o código aqui: https://github.com/uqfoundation

Mike McKerns
fonte
7
O OP não pediu built-in.
Mike McKerns
4

A abordagem a seguir parece simples e pode ser usada com variáveis ​​de tamanhos diferentes:

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)
diabo nos detalhes
fonte
hicklepacote é mais robusto (menos sujeito a erros) e ainda mais simples (menos código) do que pickle.
user2340939