Ich habe ein Objekt wie das folgende erstellt:
company1.name = 'banana'
company1.value = 40
Ich möchte dieses Objekt speichern. Wie kann ich das machen?
protocol=pickle.HIGHEST_PROTOCOL
. Meine Antwort gibt auch Alternativen zu Gurke.
Ich habe ein Objekt wie das folgende erstellt:
company1.name = 'banana'
company1.value = 40
Ich möchte dieses Objekt speichern. Wie kann ich das machen?
protocol=pickle.HIGHEST_PROTOCOL
. Meine Antwort gibt auch Alternativen zu Gurke.
Antworten:
Sie können das pickle
Modul in der Standardbibliothek verwenden. Hier ist eine elementare Anwendung auf Ihr Beispiel:
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
Sie können auch Ihr eigenes einfaches Dienstprogramm wie das folgende definieren, das eine Datei öffnet und ein einzelnes Objekt darauf schreibt:
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')
Da dies eine so beliebte Antwort ist, möchte ich einige leicht fortgeschrittene Verwendungsthemen ansprechen.
cPickle
(oder _pickle
) vs.pickle
Es ist fast immer vorzuziehen, das cPickle
Modul tatsächlich zu verwenden, anstatt pickle
weil das erstere in C geschrieben ist und viel schneller ist. Es gibt einige subtile Unterschiede zwischen ihnen, aber in den meisten Situationen sind sie gleichwertig und die C-Version bietet eine überlegene Leistung. Der Wechsel könnte nicht einfacher sein. Ändern Sie einfach die import
Anweisung wie folgt:
import cPickle as pickle
In Python 3 cPickle
wurde umbenannt _pickle
, dies ist jedoch nicht mehr erforderlich, da das pickle
Modul dies jetzt automatisch ausführt. Siehe Welcher Unterschied zwischen pickle und _pickle in Python 3? .
Der Überblick ist, dass Sie Folgendes verwenden können, um sicherzustellen, dass Ihr Code immer die C-Version verwendet, wenn er sowohl in Python 2 als auch in Python 3 verfügbar ist:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
kann Dateien in verschiedenen, Python-spezifischen Formaten lesen und schreiben, die als Protokolle bezeichnet werden, wie in der Dokumentation beschrieben . "Protokollversion 0" ist ASCII und daher "für Menschen lesbar". Versionen> 0 sind binär und die höchste verfügbare Version hängt davon ab, welche Version von Python verwendet wird. Die Standardeinstellung hängt auch von der Python-Version ab. In Python 2 war die Standardversion die Protokollversion 0
, in Python 3.8.1 die Protokollversion 4
. In Python 3.x wurde dem Modul ein Modul pickle.DEFAULT_PROTOCOL
hinzugefügt, das in Python 2 jedoch nicht vorhanden ist.
Glücklicherweise gibt es pickle.HIGHEST_PROTOCOL
in jedem Aufruf eine Abkürzung zum Schreiben (vorausgesetzt, Sie möchten dies und tun dies normalerweise). Verwenden Sie einfach die Literalzahl -1
- ähnlich wie beim Verweisen auf das letzte Element einer Sequenz über einen negativen Index. Also anstatt zu schreiben:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Sie können einfach schreiben:
pickle.dump(obj, output, -1)
In beiden Fällen hätten Sie das Protokoll nur einmal angegeben, wenn Sie ein Pickler
Objekt zur Verwendung in mehreren Pickle-Vorgängen erstellt hätten:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Hinweis : Wenn Sie sich in einer Umgebung befinden, in der verschiedene Versionen von Python ausgeführt werden, möchten Sie wahrscheinlich explizit eine bestimmte Protokollnummer verwenden (dh Hardcode), die alle lesen können (spätere Versionen können im Allgemeinen Dateien lesen, die von früheren Versionen erstellt wurden). .
Während eine Beize - Datei kann eine beliebige Anzahl von eingelegten Objekten enthält, wie in den obigen Proben gezeigt, wenn eine unbekannte Anzahl von ihnen gibt es, ist es oft einfacher , sie zu speichern alle in irgendeiner Art von variabler Größe Behältern, wie ein list
, tuple
oder dict
und Schreib sie alle in einem einzigen Aufruf in die Datei:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
und stellen Sie die Liste und alles darin später wieder her mit:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
Der große Vorteil ist , dass Sie nicht wissen müssen, wie viele Objektinstanzen , um gespeichert werden , um sie später wieder zu laden (wenn auch ohne diese Informationen so zu tun ist möglich, es einig etwas spezialisierten Code erfordert). Antworten auf die zugehörige Frage anzeigen Speichern und Laden mehrerer Objekte in einer Pickle-Datei? Einzelheiten zu verschiedenen Möglichkeiten finden Sie hier. Persönlich ich wie @Lutz Prechelt die Antwort die beste. Hier ist es an die Beispiele hier angepasst:
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
und company2
. Warum löschst du nicht auch Company
und zeigst, was passiert?
Ich denke, es ist eine ziemlich starke Annahme anzunehmen, dass das Objekt ein ist class
. Was ist, wenn es kein ist class
? Es gibt auch die Annahme, dass das Objekt nicht im Interpreter definiert wurde. Was ist, wenn es im Interpreter definiert wurde? Was wäre, wenn die Attribute dynamisch hinzugefügt würden? Wenn bei einigen Python-Objekten __dict__
nach der Erstellung Attribute hinzugefügt werden , pickle
wird das Hinzufügen dieser Attribute nicht berücksichtigt (dh es wird vergessen, dass sie hinzugefügt wurden - da sie pickle
unter Bezugnahme auf die Objektdefinition serialisiert werden).
In all diesen Fällen pickle
und cPickle
kann Sie schrecklich scheitern.
Wenn Sie eine object
(willkürlich erstellte) speichern möchten, in der Sie Attribute haben (entweder in der Objektdefinition hinzugefügt oder danach), ist es am besten dill
, diese zu verwenden , mit der fast alles in Python serialisiert werden kann.
Wir beginnen mit einer Klasse…
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)
...
>>>
Jetzt herunterfahren und neu starten ...
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
kann nicht damit umgehen. Lass es uns versuchen dill
. Wir werden einen anderen Objekttyp (a lambda
) für ein gutes Maß einwerfen .
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)
...
>>>
Und jetzt lesen Sie die Datei.
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
>>>
Es klappt. Der Grund pickle
, warum dies fehlschlägt und dill
nicht, ist, dass es (größtenteils) wie ein Modul dill
behandelt __main__
wird und auch Klassendefinitionen einbinden kann, anstatt durch Referenz zu beizen (wie es der pickle
Fall ist). Der Grund, warum a dill
eingelegt werden kann, lambda
ist, dass es ihm einen Namen gibt… dann kann Beizmagie passieren.
Tatsächlich gibt es eine einfachere Möglichkeit, alle diese Objekte zu speichern, insbesondere wenn Sie viele Objekte erstellt haben. Speichern Sie einfach die gesamte Python-Sitzung und kehren Sie später darauf zurück.
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')
>>>
Schalten Sie jetzt Ihren Computer aus, genießen Sie einen Espresso oder was auch immer und kommen Sie später wieder ...
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>
Der einzige große Nachteil ist, dass er dill
nicht Teil der Python-Standardbibliothek ist. Wenn Sie also kein Python-Paket auf Ihrem Server installieren können, können Sie es nicht verwenden.
Wenn Sie jedoch Python-Pakete auf Ihrem System installieren können, erhalten Sie die neuesten dill
Informationen git+https://github.com/uqfoundation/dill.git@master#egg=dill
. Und Sie können die neueste veröffentlichte Version mit erhalten pip install dill
.
TypeError: __new__() takes at least 2 arguments (1 given)
wenn ich versuche dill
(was vielversprechend aussieht) mit einem ziemlich komplexen Objekt zu arbeiten, das eine Audiodatei enthält.
TypeError
wenn du was genau machst? Dies ist normalerweise ein Zeichen dafür, dass beim Instanziieren einer Klasseninstanz die falsche Anzahl von Argumenten vorliegt. Wenn dies nicht Teil des Workflows der obigen Frage ist, können Sie es als eine andere Frage posten, mir per E-Mail dill
senden oder als Problem auf der Github-Seite hinzufügen?
dill
Problem war.
dil
Ich gebe mir MemoryError
aber! so tut cPickle
, pickle
und hickle
.
Sie können anycache verwenden , um die Arbeit für Sie zu erledigen. Es berücksichtigt alle Details:
pickle
Modul lambda
und alle netten Python-Funktionen erweitert werden.Angenommen, Sie haben eine Funktion, myfunc
die die Instanz erstellt:
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 ruft myfunc
beim ersten Mal auf und wählt das Ergebnis in eine Datei aus, cachedir
indem ein eindeutiger Bezeichner (abhängig vom Funktionsnamen und seinen Argumenten) als Dateiname verwendet wird. Bei jedem aufeinanderfolgenden Lauf wird das eingelegte Objekt geladen. Wenn das cachedir
zwischen Python-Läufen erhalten bleibt, wird das eingelegte Objekt aus dem vorherigen Python-Lauf übernommen.
Weitere Details finden Sie in der Dokumentation
anycache
mehr als eine Instanz von beispielsweise einem class
oder einem Container wie a speichern list
(das war nicht das Ergebnis des Aufrufs einer Funktion)?
Schnelles Beispiel company1
aus Ihrer Frage mit 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"))
Wie diese Antwort jedoch feststellte, versagt die Gurke häufig. Also solltest du wirklich verwenden 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"))