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'

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').


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

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


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

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


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)

hicklepakiet jest bardziej niezawodny (mniej podatny na błędy) i jeszcze prostszy (mniej kodu) niż pickle.
user2340939
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.