Jak zapisać i przywrócić wiele zmiennych w Pythonie?

106

Muszę zapisać do pliku kilkanaście obiektów, a następnie przywrócić je później. Próbowałem użyć pętli for z marynatą i półką, ale nie działało dobrze.

Edytować.
Wszystkie obiekty, które próbowałem zapisać, należały do ​​tej samej klasy (powinienem był o tym wcześniej wspomnieć) i nie zdawałem sobie sprawy, że mogę po prostu zapisać całą klasę w ten sposób:

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
źródło
1
Mówisz, że próbowałeś pętli for. Prześlij ten kod i dlaczego „to nie zadziałało” (tj. Co się stało i co chciałeś, aby się stało).
Blair,
Jeśli korzystasz z systemu Windows, pamiętaj, aby otworzyć pliki w trybie binarnym
John La Rooy,
@gnibbler: tryb binarny jest potrzebny tylko w przypadku protokołów innych niż domyślne ( docs.python.org/library/pickle.html#usage ).
Eric O Lebigot

Odpowiedzi:

172

Jeśli chcesz zapisać wiele obiektów, możesz po prostu umieścić je na jednej liście lub krotce, na przykład:

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)

Jeśli masz dużo danych, możesz zmniejszyć rozmiar pliku, przekazując protocol=-1do dump(); pickleużyje wtedy najlepszego dostępnego protokołu zamiast domyślnego protokołu historycznego (i bardziej kompatybilnego wstecz). W tym przypadku, należy otworzyć plik w trybie binarnym ( wbi rb, odpowiednio).

Tryb binarny powinien być również używany z Pythonem 3, ponieważ jego domyślny protokół tworzy dane binarne (tj. Nietekstowe) (tryb pisania 'wb'i tryb odczytu 'rb').

Eric O Lebigot
źródło
12
W Pythonie 3.5 musiałem otworzyć plik w trybie „bajtowym”, np. with open('objs.pickle', 'wb') as f:(Zwróć uwagę na wb).
kbrose
Cześć @ Eric, po co with open('objs.pkl') as f:po prostu porównywać obj1, obj2 = pickle.load(open("objs.pkl","rb"))? Czy jest jakaś różnica między tymi dwoma?
balandongiv
W drugim formularzu nie zamykasz pliku. Nie jest to uważane za dobrą praktykę, ponieważ liczba plików, które można otworzyć równolegle, jest zwykle dość ograniczona przez systemy operacyjne (spróbuj pętli, która otwiera pliki bez ich zamykania!). To powiedziawszy, w praktyce niezamknięcie pliku często działa, gdy nie otwiera się wielu plików.
Eric O Lebigot
51

Istnieje wbudowana biblioteka o nazwie pickle. Używając picklemożesz zrzucić obiekty do pliku i załadować je później.

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
źródło
1
I Python 3.4 używam: f = open('store.pckl', 'wb')do otwierania pliku do zapisu. Zajrzyj na stackoverflow.com/questions/13906623/ ... I użyj `f = open ('store.pckl', 'rb'), aby otworzyć plik do odczytu. Zobacz stackoverflow.com/questions/7031699/… .
user3731622
czy to jest specyficzne dla 3.4+? Prawie przegłosowałem odpowiedź, ponieważ generuje błędy, gdy nie używasz „b”.
Wilmer E. Henao
12

Powinieneś spojrzeć na półki i moduły do piklowania . Jeśli potrzebujesz przechowywać dużo danych, lepiej skorzystać z bazy danych

John La Rooy
źródło
Chcę zapisać pojedynczy obiekt, który loguje się do serwera w chmurze, aby obsłużyć, jeśli zaloguję się wiele razy w czasie, serwer odrzuci moje żądanie. Czy zrzucenie obiektu do pliku za pomocą modułu pikle może mieć jakiekolwiek problemy z bezpieczeństwem? , na przykład jeśli ktoś otrzyma mój zrzucony obiekt, może zalogować się do mojego magazynu w chmurze bez użycia hasła.
Alper
6

Innym podejściem do zapisywania wielu zmiennych w pliku marynaty jest:

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
źródło
4

Możesz użyć klepto, który zapewnia trwałe buforowanie do pamięci, dysku lub bazy danych.

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

Następnie po restarcie tłumacza ...

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

Pobierz kod tutaj: https://github.com/uqfoundation

Mike McKerns
źródło
7
OP nie poprosił o wbudowanie.
Mike McKerns
4

Poniższe podejście wydaje się proste i można je stosować ze zmiennymi o różnej wielkości:

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)
diabeł w szczegółach
źródło
hicklepakiet jest bardziej niezawodny (mniej podatny na błędy) i jeszcze prostszy (mniej kodu) niż pickle.
user2340939