Stworzyłem taki obiekt:
company1.name = 'banana'
company1.value = 40
Chciałbym zapisać ten obiekt. Jak mogę to zrobić?
protocol=pickle.HIGHEST_PROTOCOL
. Moja odpowiedź daje również alternatywy dla marynaty.
Stworzyłem taki obiekt:
company1.name = 'banana'
company1.value = 40
Chciałbym zapisać ten obiekt. Jak mogę to zrobić?
protocol=pickle.HIGHEST_PROTOCOL
. Moja odpowiedź daje również alternatywy dla marynaty.
Odpowiedzi:
Możesz użyć pickle
modułu w standardowej bibliotece. Oto podstawowe zastosowanie tego w twoim przykładzie:
import pickle
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
with open('company_data.pkl', 'wb') as output:
company1 = Company('banana', 40)
pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
company2 = Company('spam', 42)
pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as input:
company1 = pickle.load(input)
print(company1.name) # -> banana
print(company1.value) # -> 40
company2 = pickle.load(input)
print(company2.name) # -> spam
print(company2.value) # -> 42
Możesz także zdefiniować własne proste narzędzie, takie jak następujące, które otwierają plik i zapisują do niego pojedynczy obiekt:
def save_object(obj, filename):
with open(filename, 'wb') as output: # Overwrites any existing file.
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
# sample usage
save_object(company1, 'company1.pkl')
Ponieważ jest to tak popularna odpowiedź, chciałbym poruszyć kilka nieco zaawansowanych tematów użytkowania.
cPickle
(lub _pickle
) vspickle
Prawie zawsze lepiej jest używać cPickle
modułu, pickle
ponieważ ten pierwszy jest napisany w C i jest znacznie szybszy. Istnieją pewne subtelne różnice między nimi, ale w większości sytuacji są one równoważne, a wersja C zapewnia znacznie lepszą wydajność. Przejście na to nie może być łatwiejsze, wystarczy zmienić import
instrukcję na:
import cPickle as pickle
W Pythonie 3 cPickle
zmieniono nazwę _pickle
, ale robienie tego nie jest już konieczne, ponieważ pickle
moduł robi to teraz automatycznie - zobacz Jaka jest różnica między marynatą a _pickle w pythonie 3? .
Podsumowaniem jest to, że możesz użyć czegoś takiego jak poniżej, aby upewnić się, że Twój kod będzie zawsze używał wersji C, gdy jest ona dostępna zarówno w Pythonie 2, jak i 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
potrafi odczytywać i zapisywać pliki w kilku różnych, specyficznych dla Pythona formatach, zwanych protokołami, jak opisano w dokumentacji , „Protokół w wersji 0” jest ASCII, a zatem „czytelny dla człowieka”. Wersje> 0 są binarne, a najwyższy dostępny zależy od używanej wersji Pythona. Wartość domyślna zależy również od wersji Python. W Pythonie 2 domyślna była wersja protokołu 0
, ale w Python 3.8.1 jest to wersja protokołu 4
. W Pythonie 3.x moduł został pickle.DEFAULT_PROTOCOL
dodany, ale nie istnieje w Pythonie 2.
Na szczęście istnieje skrót do pisania pickle.HIGHEST_PROTOCOL
przy każdym wywołaniu (zakładając, że tego właśnie chcesz i zwykle robisz), po prostu użyj literalnej liczby -1
- podobnie do odwołania do ostatniego elementu sekwencji za pomocą indeksu ujemnego. Zamiast pisać:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Możesz po prostu napisać:
pickle.dump(obj, output, -1)
Tak czy inaczej, protokół należy określić tylko raz, jeśli utworzono Pickler
obiekt do użycia w wielu operacjach trawienia:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Uwaga : jeśli pracujesz w środowisku z różnymi wersjami Pythona, prawdopodobnie będziesz chciał jawnie użyć (tj. Kodu stałego) określonego numeru protokołu, który wszystkie mogą odczytać (późniejsze wersje mogą generalnie czytać pliki wcześniejszych wersji) .
Choć plik marynata może zawierać dowolną liczbę marynowanych obiektów, jak pokazano w powyższych próbkach, gdy pojawia się nieznany numer z nich, często łatwiej jest je wszystkie przechowywać w jakiś sposób zmienny rozmiarze pojemniku, jak list
, tuple
lub dict
i zapisu wszystkie do pliku w jednym wywołaniu:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
i przywróć listę i wszystko na niej później za pomocą:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
Główną zaletą jest to, że nie trzeba wiedzieć, ile instancji obiektów jest zapisywanych, aby załadować je później (chociaż robienie tego bez tych informacji jest możliwe, wymaga nieco specjalistycznego kodu). Zobacz odpowiedzi na powiązane pytanie Zapisywanie i ładowanie wielu obiektów w pliku pikli? po szczegóły na różne sposoby to zrobić. Osobiście I jak @Lutz Prechelt za odpowiedź najlepszy. Oto jest dostosowany do przykładów tutaj:
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickled_items(filename):
""" Unpickle a file of pickled data. """
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Companies in pickle file:')
for company in pickled_items('company_data.pkl'):
print(' name: {}, value: {}'.format(company.name, company.value))
company1
i company2
. Dlaczego też nie usuwasz Company
i nie pokazujesz, co się dzieje?
Myślę, że dość silnym założeniem jest założenie, że obiekt jest class
. Co jeśli to nie jest class
? Istnieje również założenie, że obiekt nie został zdefiniowany w tłumaczu. Co jeśli został zdefiniowany w tłumaczu? A co, jeśli atrybuty zostały dodane dynamicznie? Kiedy niektóre obiekty Pythona mają dodane atrybuty do swoich __dict__
po utworzeniu, pickle
nie szanuje dodania tych atrybutów (tzn. „Zapomina”, że zostały dodane - ponieważ pickle
serializuje przez odniesienie do definicji obiektu).
We wszystkich tych przypadkach pickle
i cPickle
może Cię okropnie zawieść.
Jeśli chcesz zapisać object
(dowolnie utworzone), w którym masz atrybuty (dodane w definicji obiektu lub później)… najlepiej jest użyć dill
, który może serializować prawie wszystko w pythonie.
Zaczynamy od klasy…
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
Teraz zamknij i uruchom ponownie ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> 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 load
return Unpickler(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'
>>>
Ups… pickle
nie mogę sobie z tym poradzić. Try Chodźmy dill
. Dla dokładności wrzucimy inny typ obiektu (a lambda
).
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
A teraz przeczytaj plik.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> 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.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
To działa. Powodem jest to, że się pickle
nie udaje, i dill
to dlatego , że dill
traktuje się __main__
jak moduł (w przeważającej części), a także może wytrawiać definicje klas zamiast wytrawiania przez odniesienie (podobnie jak pickle
robi). Powodem, dla którego dill
można marynować a, lambda
jest to, że nadaje jej nazwę… wtedy może się zdarzyć magia trawienia.
W rzeczywistości istnieje łatwiejszy sposób na zapisanie wszystkich tych obiektów, zwłaszcza jeśli masz wiele utworzonych obiektów. Zrzuć całą sesję Pythona i wróć do niej później.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
Teraz wyłącz komputer, wypij espresso lub cokolwiek innego i wróć później ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
Jedyną poważną wadą jest to, że dill
nie jest częścią standardowej biblioteki Pythona. Jeśli więc nie możesz zainstalować pakietu python na swoim serwerze, nie możesz go użyć.
Jeśli jednak jesteś w stanie zainstalować pakiety Pythona w swoim systemie, możesz uzyskać najnowsze dill
z git+https://github.com/uqfoundation/dill.git@master#egg=dill
. I możesz uzyskać najnowszą wydaną wersję za pomocą pip install dill
.
TypeError: __new__() takes at least 2 arguments (1 given)
gdy próbuję użyć dill
(co wygląda obiecująco) z dość złożonym obiektem, który zawiera plik audio.
TypeError
moment, kiedy robisz co dokładnie? Zazwyczaj jest to oznaka niepoprawnej liczby argumentów podczas tworzenia instancji klasy. Jeśli nie jest to część przepływu pracy powyższego pytania, czy możesz opublikować je jako inne pytanie, przesłać je do mnie e-mailem lub dodać jako problem na stronie dill
github?
dill
problemu.
dil
Daje mi MemoryError
jednak! tak robi cPickle
, pickle
i hickle
.
Możesz użyć Anycache, aby wykonać zadanie za Ciebie. Uwzględnia wszystkie szczegóły:
pickle
moduł Pythona do obsługi lambda
i wszystkich fajnych funkcji Pythona.Zakładając, że masz funkcję, myfunc
która tworzy instancję:
from anycache import anycache
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')
def myfunc(name, value)
return Company(name, value)
Anycache wywołuje myfunc
po raz pierwszy i wybiera wynik do pliku, cachedir
używając unikalnego identyfikatora (w zależności od nazwy funkcji i jej argumentów) jako nazwy pliku. Przy każdym kolejnym uruchomieniu ładowany obiekt jest ładowany. Jeśli cachedir
zachowane jest między uruchomieniami Pythona, piklowany obiekt jest pobierany z poprzedniego uruchomienia Pythona.
W celu uzyskania dalszych informacji patrz dokumentacja
anycache
można zapisać więcej niż jedną instancję, powiedzmy, a class
lub kontenera takiego jak list
(to nie był wynik wywołania funkcji)?
Szybki przykład company1
z wykorzystaniem pytania z 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"))
Jednak, jak zauważono w tej odpowiedzi , marynata często zawodzi. Więc powinieneś naprawdę użyć 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"))