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ć 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:
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
exceptModuleNotFoundError:import pickle
Formaty strumieni danych (protokoły)
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:
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) .
Wiele obiektów
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:
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:
classCompany: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:whileTrue:try:yield pickle.load(f)exceptEOFError:breakprint('Companies in pickle file:')for company in pickled_items('company_data.pkl'):print(' name: {}, value: {}'.format(company.name, company.value))
Jest to dla mnie rzadkie, ponieważ wyobrażałem sobie, że będzie łatwiejszy sposób na zapisanie obiektu ... Coś w rodzaju „saveobject (company1, c: \ mypythonobjects)
Peterstone,
4
@Peterstone: Jeśli chciałbyś przechowywać tylko jeden obiekt, potrzebowałbyś tylko o połowę mniej kodu niż w moim przykładzie - celowo napisałem to tak, jak to zrobiłem, aby pokazać, w jaki sposób można zapisać więcej niż jeden obiekt (a później przeczytać ponownie z) ten sam plik.
martineau,
1
@Peterstone, istnieje bardzo dobry powód do rozdzielenia obowiązków. W ten sposób nie ma ograniczeń co do sposobu wykorzystania danych z procesu wytrawiania. Możesz zapisać go na płycie lub wysłać przez połączenie sieciowe.
Harald Scheirich,
3
@martinaeau, było to w odpowiedzi na perstones Uwaga, że jedna powinna mieć tylko jedną funkcję do zapisania obiektu na dysku. Odpowiedzialność pikli polega tylko na przekształceniu obiektu w dane, które mogą być przetwarzane jako porcja. Odpowiedzialność za zapisywanie plików należy do obiektów plików. Utrzymując rzeczy oddzielić jeden umożliwia ponowne wykorzystanie np wyższy jest w stanie przesłać dane marynowane po drugiej stronie połączenia sieciowego lub przechowywanie go w bazie danych, wszystkie obowiązki oddzielić od rzeczywistych danych <-> konwersja obiektu
Harald Scheirich
1
Usuwasz company1i company2. Dlaczego też nie usuwasz Companyi nie pokazujesz, co się dzieje?
Mike McKerns,
49
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…
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwin
Type"help","copyright","credits"or"license"for more information.>>>import pickle
>>>classCompany:...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 ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.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
returnUnpickler(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).
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwin
Type"help","copyright","credits"or"license"for more information.>>>import dill
>>>classCompany:...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.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.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.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwin
Type"help","copyright","credits"or"license"for more information.>>>import dill
>>>classCompany:...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 ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.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.
Dostaję się, 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.
MikeiLL
1
@MikeiLL: Dostajesz 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?
Mike McKerns
3
Dla każdego, kto podąża za nim, oto powiązane pytanie @MikeLL - z odpowiedzi najwyraźniej nie było dillproblemu.
martineau,
dilDaje mi MemoryErrorjednak! tak robi cPickle, picklei hickle.
Färid Alijani,
4
Możesz użyć Anycache, aby wykonać zadanie za Ciebie. Uwzględnia wszystkie szczegóły:
Używa kopru jako backendu, który rozszerza picklemoduł Pythona do obsługi lambdai wszystkich fajnych funkcji Pythona.
Przechowuje różne obiekty w różnych plikach i ładuje je poprawnie.
Ogranicza rozmiar pamięci podręcznej
Umożliwia czyszczenie pamięci podręcznej
Umożliwia współdzielenie obiektów między wieloma przebiegami
Pozwala na poszanowanie plików wejściowych, które wpływają na wynik
Zakładając, że masz funkcję, myfuncktóra tworzy instancję:
from anycache import anycache
classCompany(object):def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')def myfunc(name, value)returnCompany(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
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: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:
Aktualizacja
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: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:
Formaty strumieni danych (protokoły)
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łu0
, ale w Python 3.8.1 jest to wersja protokołu4
. 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ć:Możesz po prostu napisać:
Tak czy inaczej, protokół należy określić tylko raz, jeśli utworzono
Pickler
obiekt do użycia w wielu operacjach trawienia: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) .
Wiele obiektów
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
lubdict
i zapisu wszystkie do pliku w jednym wywołaniu:i przywróć listę i wszystko na niej później za pomocą:
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:
źródło
company1
icompany2
. Dlaczego też nie usuwaszCompany
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 jestclass
? 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
icPickle
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…
Teraz zamknij i uruchom ponownie ...
Ups…
pickle
nie mogę sobie z tym poradzić. Try Chodźmydill
. Dla dokładności wrzucimy inny typ obiektu (alambda
).A teraz przeczytaj plik.
To działa. Powodem jest to, że się
pickle
nie udaje, idill
to dlatego , żedill
traktuje się__main__
jak moduł (w przeważającej części), a także może wytrawiać definicje klas zamiast wytrawiania przez odniesienie (podobnie jakpickle
robi). Powodem, dla któregodill
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.
Teraz wyłącz komputer, wypij espresso lub cokolwiek innego i wróć później ...
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
zgit+https://github.com/uqfoundation/dill.git@master#egg=dill
. I możesz uzyskać najnowszą wydaną wersję za pomocąpip install dill
.źródło
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 stroniedill
github?dill
problemu.dil
Daje miMemoryError
jednak! tak robicPickle
,pickle
ihickle
.Możesz użyć Anycache, aby wykonać zadanie za Ciebie. Uwzględnia wszystkie szczegóły:
pickle
moduł Pythona do obsługilambda
i wszystkich fajnych funkcji Pythona.Zakładając, że masz funkcję,
myfunc
która tworzy instancję: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ślicachedir
zachowane jest między uruchomieniami Pythona, piklowany obiekt jest pobierany z poprzedniego uruchomienia Pythona.W celu uzyskania dalszych informacji patrz dokumentacja
źródło
anycache
można zapisać więcej niż jedną instancję, powiedzmy, aclass
lub kontenera takiego jaklist
(to nie był wynik wywołania funkcji)?Szybki przykład
company1
z wykorzystaniem pytania z python3.Jednak, jak zauważono w tej odpowiedzi , marynata często zawodzi. Więc powinieneś naprawdę użyć
dill
.źródło