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ć picklemoduł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) vspicklePrawie zawsze lepiej jest używać cPicklemodułu, pickleponieważ 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ć importinstrukcję na:
import cPickle as pickle
W Pythonie 3 cPicklezmieniono nazwę _pickle, ale robienie tego nie jest już konieczne, ponieważ picklemoduł 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
picklepotrafi 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_PROTOCOLdodany, ale nie istnieje w Pythonie 2.
Na szczęście istnieje skrót do pisania pickle.HIGHEST_PROTOCOLprzy 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 Picklerobiekt 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, tuplelub dicti 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))
company1i company2. Dlaczego też nie usuwasz Companyi 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, picklenie szanuje dodania tych atrybutów (tzn. „Zapomina”, że zostały dodane - ponieważ pickleserializuje przez odniesienie do definicji obiektu).
We wszystkich tych przypadkach picklei cPicklemoż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… picklenie 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ę picklenie udaje, i dillto dlatego , że dilltraktuje się __main__jak moduł (w przeważającej części), a także może wytrawiać definicje klas zamiast wytrawiania przez odniesienie (podobnie jak picklerobi). Powodem, dla którego dillmożna marynować a, lambdajest 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 dillnie 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 dillz 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.
TypeErrormoment, 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 dillgithub?
dillproblemu.
dilDaje mi MemoryErrorjednak! tak robi cPickle, picklei hickle.
Możesz użyć Anycache, aby wykonać zadanie za Ciebie. Uwzględnia wszystkie szczegóły:
picklemoduł Pythona do obsługi lambdai wszystkich fajnych funkcji Pythona.Zakładając, że masz funkcję, myfuncktó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 myfuncpo raz pierwszy i wybiera wynik do pliku, cachediruż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 cachedirzachowane jest między uruchomieniami Pythona, piklowany obiekt jest pobierany z poprzedniego uruchomienia Pythona.
W celu uzyskania dalszych informacji patrz dokumentacja
anycachemożna zapisać więcej niż jedną instancję, powiedzmy, a classlub kontenera takiego jak list(to nie był wynik wywołania funkcji)?
Szybki przykład company1z 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"))