Ich habe ein Objekt wie dieses erstellt:
company1.name = 'banana'
company1.value = 40
Ich möchte dieses Objekt speichern. Wie kann ich das machen?
Sie können das Modul pickle
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 Hilfsprogramm 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 auf ein paar etwas fortgeschrittene Verwendungsthemen eingehen.
cPickle
(oder _pickle
) vs pickle
Es ist fast immer vorzuziehen, das cPickle
-Modul anstelle von pickle
zu verwenden, da 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. Es könnte nicht einfacher sein, dorthin zu wechseln. Ändern Sie einfach die Anweisung import
wie folgt:
import cPickle as pickle
In Python 3 wurde cPickle
umbenannt _pickle
, dies ist jedoch nicht mehr erforderlich, da das Modul pickle
dies jetzt automatisch ausführt - siehe Welcher Unterschied zwischen pickle und _pickle in python= 3? =.
Das Problem ist, dass Sie Folgendes verwenden können, um sicherzustellen, dass Ihr Code immer die C-Version verwendet, wenn sie sowohl in Python 2 als auch in === (Python $ === 2) verfügbar ist 3:
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 Dokumentation , "Protokoll" beschrieben version 0 "ist ASCII und daher" lesbar ". Versionen> 1 sind binär und die höchste verfügbare Version hängt davon ab, welche Version von Python verwendet wird Der Standard hängt auch von der Python Version ab. In Python 2 war der Standard die Protokollversion 0
, aber in Python 3.7 ist es Protokollversion 3
. In Python 3.x hatte das Modul ein pickle.DEFAULT_PROTOCOL
hinzugefügt, aber das existiert nicht in Python 2.
Zum Glück gibt es eine Abkürzung zum Schreiben von pickle.HIGHEST_PROTOCOL
Verwenden Sie bei jedem Anruf (vorausgesetzt, Sie möchten und tun dies in der Regel) einfach die wörtliche Nummer -1
- Ähnlich wie beim Referenzieren des letzten Elements 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 müssten Sie das Protokoll nur einmal angeben, wenn Sie ein Pickler
-Objekt zur Verwendung in mehreren Beizvorgä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 Python-Versionen ausgeführt werden, möchten Sie wahrscheinlich explizit eine bestimmte Protokollnummer (dh einen Hardcode) verwenden, die von allen gelesen werden kann (Spätere Versionen können im Allgemeinen Dateien lesen, die von früheren Versionen erstellt wurden.).
Während eine Pickle-Datei eine beliebige Anzahl von gebeizten Objekten enthalten kann , wie in den obigen Beispielen gezeigt, ist es oft einfacher, sie alle in irgendeiner Form zu speichern, wenn eine unbekannte Anzahl vorhanden ist Container mit variabler Größe, wie ein list
, Tuple
oder dict
, und schreiben Sie 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 stelle die Liste und alles darin später wieder her mit:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
Der Hauptvorteil ist, dass Sie nicht wissen müssen, wie viele Objektinstanzen gespeichert sind, um sie später wieder zu laden (obwohl dies ohne diese Informationen möglich ist , erfordert es einige geringfügige Spezialcode). Siehe die Antworten auf die entsprechende Frage Speichern und Laden mehrerer Objekte in einer Pickle-Datei? für Einzelheiten zu den verschiedenen Möglichkeiten. Persönlich [~ # ~] Ich [~ # ~] mag @Lutz Prechelt's Antwort das Beste. Hier ist es den Beispielen 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))
Ich denke, es ist eine ziemlich starke Annahme, dass das Objekt ein class
ist. Was ist, wenn es kein class
ist? Es gibt auch die Annahme, dass das Objekt nicht im Interpreter definiert wurde. Was ist, wenn es im Interpreter definiert wurde? Was ist auch, wenn die Attribute dynamisch hinzugefügt wurden? Wenn bei einigen python - Objekten nach der Erstellung Attribute zu ihrem __dict__
Hinzugefügt wurden, beachtet pickle
das Hinzufügen dieser Attribute nicht (dh es "vergisst", was sie waren) hinzugefügt - weil pickle
durch Bezugnahme auf die Objektdefinition serialisiert wird).
In all diesen Fällen können pickle
und cPickle
schrecklich versagen.
Wenn Sie ein object
(willkürlich erstellt) speichern möchten, in dem Sie Attribute haben (entweder in der Objektdefinition hinzugefügt oder danach), sollten Sie dill
verwenden, das serialisiert werden kann fast alles in Python.
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'
>>>
Hoppla ... pickle
kann damit nicht umgehen. Versuchen wir es mit dill
. Wir werden einen anderen Objekttyp (ein 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 lies 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, warum pickle
fehlschlägt und dill
nicht, ist, dass dill
__main__
(Größtenteils) wie ein Modul behandelt und auch pickeln kann Klassendefinitionen statt Beizen durch Referenz (wie es pickle
tut). Der Grund, warum dill
ein lambda
einsammeln kann, ist, dass es einen Namen hat ... dann kann es zu Magie kommen.
Tatsächlich gibt es eine einfachere Möglichkeit, alle diese Objekte zu speichern, insbesondere wenn Sie viele Objekte erstellt haben. Entleere einfach die gesamte python Sitzung und komme 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')
>>>
Fahren Sie jetzt Ihren Computer herunter, 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 dill
nicht Teil der python Standardbibliothek ist. Wenn Sie also kein python Paket auf installieren können Ihr Server, dann können Sie es nicht verwenden.
Wenn Sie jedoch in der Lage sind, python Pakete auf Ihrem System zu installieren, können Sie mit git+https://github.com/uqfoundation/[email protected]#Egg=dill
Das neueste dill
und die neueste veröffentlichte Version erhalten mit pip install dill
.
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 Nice python Funktionen.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 zum ersten Mal myfunc
auf und kopiert das Ergebnis in eine Datei in cachedir
, wobei ein eindeutiger Bezeichner (abhängig vom Funktionsnamen und seinen Argumenten) als Dateiname verwendet wird. Bei jedem nachfolgenden Durchlauf wird das eingelegte Objekt geladen. Wenn das cachedir
zwischen python Läufen beibehalten wird, wird das ausgewählte Objekt aus dem vorherigen python Läufen übernommen.
Für weitere Details siehe Dokumentation