Ich habe ein Objekt wie dieses erstellt:
company1.name = 'Banane'
company1.value = 40
Ich möchte dieses Objekt speichern. Wie kann ich das tun?
Ich habe ein Objekt wie dieses erstellt:
company1.name = 'Banane'
company1.value = 40
Ich möchte dieses Objekt speichern. Wie kann ich das tun?
Sie könnten das pickle
Modul in der Standardbibliothek verwenden. Hier ist eine einfache Anwendung davon 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 outp:
company1 = Company('Banane', 40)
pickle.dump(company1, outp, pickle.HIGHEST_PROTOCOL)
company2 = Company('Spam', 42)
pickle.dump(company2, outp, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as inp:
company1 = pickle.load(inp)
print(company1.name) # -> Banane
print(company1.value) # -> 40
company2 = pickle.load(inp)
print(company2.name) # -> Spam
print(company2.value) # -> 42
Sie könnten auch Ihr eigenes einfaches Dienstprogramm definieren, das wie folgt fungiert und eine Datei öffnet und ein einzelnes Objekt darin schreibt:
def save_object(obj, dateiname):
with open(dateiname, 'wb') as outp: # überschreibt eine vorhandene Datei.
pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL)
# beispielhafte Verwendung
save_object(company1, 'firma1.pkl')
Da dies eine so beliebte Antwort ist, möchte ich einige leicht fortgeschrittene Themen ansprechen.
cPickle
(oder _pickle
) vs pickle
Es ist fast immer vorzuziehen, tatsächlich das cPickle
Modul anstelle von pickle
zu verwenden, da ersteres in C geschrieben ist und wesentlich schneller ist. Es gibt einige subtile Unterschiede zwischen ihnen, aber in den meisten Situationen sind sie äquivalent und die C-Version bietet deutlich bessere Leistung. Das Umschalten darauf ist sehr einfach, ändern Sie einfach die import
Anweisung zu:
import cPickle as pickle
In Python 3 wurde cPickle
in _pickle
umbenannt, aber dies ist nicht mehr notwendig, da das pickle
Modul dies jetzt automatisch macht. Siehe Was ist der Unterschied zwischen pickle und _pickle in Python 3?.
Die Zusammenfassung ist, dass Sie etwas Ähnliches verwenden könnten, um sicherzustellen, dass Ihr Code immer die C-Version verwendet, wenn sie in beiden Python 2 und 3 verfügbar ist:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
kann Dateien in verschiedenen, Python-spezifischen Formaten lesen und schreiben, sogenannten Protokollen, wie in der Dokumentation beschrieben. "Protokollversion 0" ist ASCII und daher "menschlich lesbar". Versionen > 0 sind binär und die höchste verfügbare hängt davon ab, welche Python-Version verwendet wird. Der Standard hängt auch von der Python-Version ab. In Python 2 war der Standard Protokollversion 0
, aber in Python 3.8.1 ist es Protokollversion 4
. Im Modul in Python 3.x wurde pickle.DEFAULT_PROTOCOL
hinzugefügt, das gibt es aber in Python 2 nicht.
Glücklicherweise gibt es eine Abkürzung, um pickle.HIGHEST_PROTOCOL
bei jedem Aufruf zu schreiben (vorausgesetzt, das ist, was Sie wollen, und normalerweise ist es das), verwenden Sie einfach die buchstäbliche Zahl -1
- ähnlich dem Aufrufen des letzten Elements einer Sequenz über einen negativen Index. Anstatt also zu schreiben:
pickle.dump(obj, outp, pickle.HIGHEST_PROTOCOL)
kannst du einfach schreiben:
pickle.dump(obj, outp, -1)
Auf diese Weise müssen Sie das Protokoll nur einmal angeben, wenn Sie ein Pickler
Objekt für die Verwendung in mehreren Pickle-Operationen erstellen:
pickler = pickle.Pickler(outp, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Hinweis: Wenn Sie in einer Umgebung mit verschiedenen Python-Versionen arbeiten, sollten Sie wahrscheinlich eine bestimmte Protokollnummer explizit verwenden (dh fest codieren), die alle lesen können (spätere Versionen können im Allgemeinen Dateien lesen, die von früheren erstellt wurden).
Obwohl eine Pickle-Datei beliebig viele gepickelte Objekte enthalten kann, wie in den obigen Beispielen gezeigt, wenn die Anzahl unbekannt ist, ist es oft einfacher, sie alle in einer Art variabler Container, wie einer list
, tuple
oder dict
zu speichern und sie alle gleichzeitig in einer einzigen Anweisung in die Datei zu schreiben:
tech_firmen = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_firmen, 'tech_firmen.pkl')
und die Liste und alles in ihr später mit folgendem wiederherzustellen:
with open('tech_firmen.pkl', 'rb') as inp:
tech_firmen = pickle.load(inp)
Der Hauptvorteil ist, dass Sie nicht wissen müssen, wie viele Objektinstanzen gespeichert sind, um sie später zurückzuladen (obwohl das ohne diese Information möglich ist, erfordert es etwas spezialisierten Code). Sehen Sie die Antworten auf die verwandte Frage Speichern und Laden mehrerer Objekte in Pickle-Datei? für Details zu verschiedenen Möglichkeiten, dies zu tun. Persönlich mochte ich @Lutz Prechelt's Antwort am besten, daher wird darin im folgenden Beispielcode verwendet:
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickle_loader(dateiname):
""" Deserialisieren einer Datei mit gepickelten Objekten. """
with open(dateiname, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Unternehmen in Pickle-Datei:')
for firma in pickle_loader('firma_datum.pkl'):
print(' name: {}, wert: {}'.format(firma.name, firma.value))
Dies ist für mich selten, weil ich mir vorgestellt habe, dass es eine einfachere Möglichkeit geben würde, ein Objekt zu speichern... Etwas wie 'saveobject(company1,c:\mypythonobjects)
@Peterstone: Wenn Sie nur ein Objekt speichern möchten, benötigen Sie nur etwa halb so viel Code wie in meinem Beispiel - ich habe es absichtlich so geschrieben, um zu zeigen, wie mehr als ein Objekt in dieselbe Datei gespeichert (und später wieder gelesen) werden könnte.
@Peterstone, es gibt einen sehr guten Grund für die Trennung der Verantwortlichkeiten. Auf diese Weise gibt es keine Einschränkung, wie die Daten aus dem Einmachprozess verwendet werden. Sie können sie auf die Festplatte speichern oder sie auch über eine Netzwerkverbindung senden.
Ich denke, es ist eine ziemlich starke Annahme anzunehmen, dass das Objekt eine Klasse
ist. Was ist, wenn es keine Klasse
ist? Es gibt auch die Annahme, dass das Objekt nicht im Interpreter definiert wurde. Was, wenn es im Interpreter definiert wurde? Außerdem, was ist, wenn die Attribute dynamisch hinzugefügt wurden? Wenn einigen Python-Objekten nach der Erstellung Attribute zu ihrem __dict__
hinzugefügt werden, respektiert pickle
nicht die Hinzufügung dieser Attribute (d. h. es 'vergisst', dass sie hinzugefügt wurden - weil pickle
durch Verweis auf die Objektdefinition serialisiert).
In all diesen Fällen können pickle
und cPickle
dich schrecklich im Stich lassen.
Wenn du versuchst, ein Objekt
(beliebig erstellt) zu speichern, bei dem du Attribute hast (entweder in der Objektdefinition hinzugefügt oder danach)... ist deine beste Wahl, dill
zu verwenden, das fast alles in Python serialisieren kann.
Wir fangen mit einer Klasse an...
Python 2.7.8 (default, 13. Juli 2014, 02:29:54)
[GCC 4.2.1 Kompatibles Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] auf Darvin
Geben Sie "help", "copyright", "credits" oder "license" für mehr Informationen ein.
>>> import pickle
>>> class Firma:
... pass
...
>>> firma1 = Firma()
>>> firma1.name = 'Banane'
>>> firma1.wert = 40
>>> with open('firma.pkl', 'wb') as f:
... pickle.dump(firma1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
Jetzt herunterfahren und neu starten...
Python 2.7.8 (default, 13. Juli 2014, 02:29:54)
[GCC 4.2.1 Kompatibles Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] auf Darvin
Geben Sie "help", "copyright", "credits" oder "license" für mehr Informationen ein.
>>> import pickle
>>> with open('firma.pkl', 'rb') as f:
... firma1 = pickle.load(f)
...
Traceback (Die aktuellste letzte Anwendung):
Datei "", Zeile 2, in
Datei "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", Zeile 1378, in load
return Entpacker(file).load()
Datei "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", Zeile 858, in load
dispatch[key](self)
Datei "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", Zeile 1090, in load_global
klass = self.find_class(module, name)
Datei "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", Zeile 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'Modul' Objekt hat kein Attribut 'Firma'
>>>
Oops... pickle
kann damit nicht umgehen. Lass uns dill
versuchen. Wir werden eine weitere Objektart hinzufügen (ein lambda
) zur Sicherheit.
Python 2.7.8 (default, 13. Juli 2014, 02:29:54)
[GCC 4.2.1 Kompatibles Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] auf Darvin
Geben Sie "help", "copyright", "credits" oder "license" für mehr Informationen ein.
>>> import dill
>>> class Firma:
... pass
...
>>> firma1 = Firma()
>>> firma1.name = 'Banane'
>>> firma1.wert = 40
>>>
>>> firma2 = lambda x:x
>>> firma2.name = 'Rhabarber'
>>> firma2.wert = 42
>>>
>>> with open('firma_dill.pkl', 'wb') as f:
... dill.dump(firma1, f)
... dill.dump(firma2, f)
...
>>>
Und jetzt die Datei lesen.
Python 2.7.8 (default, 13. Juli 2014, 02:29:54)
[GCC 4.2.1 Kompatibles Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] auf Darvin
Geben Sie "help", "copyright", "credits" oder "license" für mehr Informationen ein.
>>> import dill
>>> with open('firma_dill.pkl', 'rb') as f:
... firma1 = dill.load(f)
... firma2 = dill.load(f)
...
>>> firma1
<__main__.Firma Instanz bei 0x107909128>
>>> firma1.name
'Banane'
>>> firma1.wert
40
>>> firma2.name
'Rhabarber'
>>> firma2.wert
42
>>>
Es funktioniert. Der Grund, warum pickle
versagt und dill
nicht, liegt darin, dass dill
__main__
wie ein Modul behandelt (weitgehend) und auch Klassendefinitionen anstelle von Referenzen pickeln kann (wie pickle
es tut). Der Grund, warum dill
ein lambda
einwecken kann, ist, dass es ihm einen Namen gibt... dann kann die Pöckelmagie passieren.
Eigentlich gibt es einen einfacheren Weg, all diese Objekte zu speichern, insbesondere wenn du viele Objekte erstellt hast. Speichere einfach die gesamte Python-Sitzung und komm später darauf zurück.
Python 2.7.8 (default, 13. Juli 2014, 02:29:54)
[GCC 4.2.1 Kompatibles Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] auf Darvin
Geben Sie "help", "copyright", "credits" oder "license" für mehr Informationen ein.
>>> import dill
>>> class Firma:
... pass
...
>>> firma1 = Firma()
>>> firma1.name = 'Banane'
>>> firma1.wert = 40
>>>
>>> firma2 = lambda x:x
>>> firma2.name = 'Rhabarber'
>>> firma2.wert = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
Jetzt deinen Computer herunterfahren, einen Espresso genießen oder was auch immer, und später zurückkommen...
Python 2.7.8 (default, 13. Juli 2014, 02:29:54)
[GCC 4.2.1 Kompatibles Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] auf Darvin
Geben Sie "help", "copyright", "credits" oder "license" für mehr Informationen ein.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> firma1.name
'Banane'
>>> firma1.wert
40
>>> firma2.name
'Rhabarber'
>>> firma2.wert
42
>>> firma2
bei 0x1065f2938>
Der einzige große Nachteil ist, dass dill
nicht Teil der Python-Standardbibliothek ist. Also wenn du kein Python-Paket auf deinem Server installieren kannst, kannst du es nicht verwenden.
Wenn du jedoch in der Lage bist, Python-Pakete auf deinem System zu installieren, kannst du die neueste Version von dill
mit git+https://github.com/uqfoundation/dill.git@master#egg=dill
erhalten. Und du kannst die neueste veröffentlichte Version mit pip install dill
bekommen.
Ich erhalte einen TypeError: __new__() erfordert mindestens 2 Argumente (1 gegeben)
Fehler, wenn ich versuche, dill
(das vielversprechend aussieht) mit einem ziemlich komplexen Objekt zu verwenden, das eine Audiodatei enthält.
@MikeiLL: Sie erhalten einen TypeError
, wenn Sie was genau tun? Das ist normalerweise ein Anzeichen dafür, dass Sie die falsche Anzahl von Argumenten beim Instanziieren einer Klasseninstanz haben. Wenn dies nicht Teil des Workflows der obigen Frage ist, könnten Sie es als eine weitere Frage posten, mir per E-Mail senden oder es als Problem auf der dill
GitHub-Seite hinzufügen.
Für alle, die mitlesen, hier ist die verwandte Frage, die @MikeLL gepostet hat - laut der Antwort war es anscheinend kein dill
Problem.
Schnelles Beispiel mit company1
aus Ihrer Fragestellung, mit python3.
import pickle
# Datei speichern
pickle.dump(company1, file = open("company1.pickle", "wb"))
# Datei neu laden
company1_reloaded = pickle.load(open("company1.pickle", "rb"))
Allerdings, wie diese Antwort bemerkte, scheitert `pickle` oft. Deshalb sollten Sie wirklich dill
verwenden.
import dill
# Datei speichern
dill.dump(company1, file = open("company1.pickle", "wb"))
# Datei neu laden
company1_reloaded = dill.load(open("company1.pickle", "rb"))
Sie können anycache verwenden, um die Arbeit für Sie zu erledigen. Es berücksichtigt alle Details:
pickle
-Modul erweitert, um lambda
und alle netten Python-Funktionen zu verarbeiten.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 pickelt das Ergebnis in eine Datei in cachedir
mit einem eindeutigen Bezeichner (abhängig vom Funktionsnamen und den Argumenten) als Dateiname. Bei jedem weiteren Durchlauf wird das gepickelte Objekt geladen. Wenn das cachedir
zwischen den Python-Durchläufen erhalten bleibt, wird das gepickelte Objekt vom vorherigen Python-Durchlauf verwendet.
Für weitere Details siehe die Dokumentation
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.
3 Stimmen
Siehe Beispiel für Leute, die hierher kommen, um ein einfaches Beispiel dafür zu sehen, wie man pickle benutzt.
0 Stimmen
@MartinThoma: Warum ziehst du diese Antwort (scheinbar) der akzeptierten (von der verlinkten Frage) vor?
0 Stimmen
Zum Zeitpunkt, als ich verlinkt habe, enthielt die akzeptierte Antwort nicht
protocol=pickle.HIGHEST_PROTOCOL
. Meine Antwort gibt auch Alternativen zu pickle.