Speichern und Laden von Objekten und Verwenden von Gurke

114

Ich versuche Objekte mit pickleModul zu speichern und zu laden .
Zuerst erkläre ich meine Objekte:

>>> class Fruits:pass
...
>>> banana = Fruits()

>>> banana.color = 'yellow'
>>> banana.value = 30

Danach öffne ich eine Datei mit dem Namen 'Fruits.obj' (zuvor habe ich eine neue TXT-Datei erstellt und 'Fruits.obj' umbenannt):

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)

Danach schließe ich meine Sitzung und beginne eine neue und setze die nächste (versuche auf das Objekt zuzugreifen, das gespeichert werden soll):

file = open("Fruits.obj",'r')
object_file = pickle.load(file)

Aber ich habe diese Nachricht:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
ValueError: read() from the underlying stream did notreturn bytes

Ich weiß nicht, was ich tun soll, weil ich diese Nachricht nicht verstehe. Weiß jemand, wie ich mein Objekt 'Banane' laden kann? Danke dir!

EDIT: Wie einige von Ihnen vorgeschlagen haben, habe ich gesagt:

>>> import pickle
>>> file = open("Fruits.obj",'rb')

Es gab kein Problem, aber das nächste, das ich sagte, war:

>>> object_file = pickle.load(file)

Und ich habe Fehler:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError
Peterstone
quelle

Antworten:

74

Wie für Ihr zweites Problem:

 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "C:\Python31\lib\pickle.py", line
 1365, in load encoding=encoding,
 errors=errors).load() EOFError

Nachdem Sie den Inhalt der Datei gelesen haben, befindet sich der Dateizeiger am Ende der Datei. Es sind keine weiteren Daten zu lesen. Sie müssen die Datei zurückspulen, damit sie wieder von Anfang an gelesen wird:

file.seek(0)

Normalerweise möchten Sie jedoch einen Kontextmanager verwenden, um die Datei zu öffnen und Daten daraus zu lesen. Auf diese Weise wird die Datei nach Abschluss der Ausführung des Blocks automatisch geschlossen. Dies hilft Ihnen auch dabei, Ihre Dateivorgänge in sinnvolle Abschnitte zu organisieren.

Schließlich ist cPickle eine schnellere Implementierung des Pickle-Moduls in C. Also:

In [1]: import cPickle

In [2]: d = {"a": 1, "b": 2}

In [4]: with open(r"someobject.pickle", "wb") as output_file:
   ...:     cPickle.dump(d, output_file)
   ...:

# pickle_file will be closed at this point, preventing your from accessing it any further

In [5]: with open(r"someobject.pickle", "rb") as input_file:
   ...:     e = cPickle.load(input_file)
   ...:

In [7]: print e
------> print(e)
{'a': 1, 'b': 2}
Jim Brissom
quelle
Was für eine Datenstruktur ist das 'd = {"a": 1, "b": 2}'?
Peterstone
1
@ Peterstone: Erstellt {"a": 1, "b": 2}ein Wörterbuch mit den Schlüsseln "a"und "b"darin. Dies wird in der Online-Dokumentation als Wörterbuchanzeigeausdruck bezeichnet . Dies ist nur eine von mehreren Möglichkeiten, wie ein Objekt vom Typ dict, bei dem es sich um einen von mehreren in Python integrierten Standarddatentypen handelt, erstellt werden kann.
Martineau
2
Warum setzt der Buchstabe 'r' den Dateinamen fort? Ich sehe das nicht in den Dokumenten. Außerdem ist es schwierig, eine Variable für den Dateinamen zu verwenden.
SherylHohman
7
Wenn Sie sich diese Antwort heute ansehen und feststellen, dass sie nur für Python 2.x gilt. In Python 3.x sollte man direkt das verwenden pickle, das cpickleautomatisch importiert wird, wenn es kann. docs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp
41

Folgendes funktioniert für mich:

class Fruits: pass

banana = Fruits()

banana.color = 'yellow'
banana.value = 30

import pickle

filehandler = open("Fruits.obj","wb")
pickle.dump(banana,filehandler)
filehandler.close()

file = open("Fruits.obj",'rb')
object_file = pickle.load(file)
file.close()

print(object_file.color, object_file.value, sep=', ')
# yellow, 30
Martineau
quelle
Das funktioniert bei mir, aber ich möchte eine Sitzung schließen, eine neue öffnen und das laden, was ich in einer früheren Sitzung gespeichert habe. Ich schließe die Sitzung, nachdem ich die Zeile "filehandler.close ()" eingefügt habe, öffne eine neue und füge den Rest Ihres Codes ein. Nach dem Eingeben von "object_file = pickle.load (file)" erhalte ich folgende Fehlermeldung: Traceback ( letzter Aufruf zuletzt): Datei "<pyshell # 5>", Zeile 1, in <module> object_file = pickle.load (Datei) Datei "C: \ Python31 \ lib \ pickle.py", Zeile 1365, in Ladecodierung = Kodierung, Fehler = Fehler) .load () AttributeError: 'Modul'-Objekt hat kein Attribut' Früchte '
Peterstone
3
@Peterstone: In der zweiten Sitzung müssen Sie eine Definition von class Fruitsdefiniert haben, damit pickle.load()das Objekt aus den Daten wiederhergestellt werden kann, die in der Binärdatei gespeichert wurden. Die beste Vorgehensweise für diese Art von Dingen besteht darin, die class FruitsDefinition in einer separaten .py-Datei abzulegen (wodurch sie zu einem benutzerdefinierten Modul wird) und dann importdas Modul oder die Elemente daraus, wann immer dies erforderlich ist (dh beide Sitzungen). Wenn Sie es beispielsweise in eine Datei mit dem Namen MyDataDefs.pyeinfügen, können Sie schreiben from MyDataDefs import Fruits. Lassen Sie mich wissen, wenn dies unklar ist, und ich werde meine Antwort entsprechend aktualisieren.
Martineau
Tatsächlich empfiehlt PEP 8, alle Kleinbuchstaben für Modulnamen zu verwenden, daher sollte das Beispiel am Ende meines letzten Kommentars in einer Datei mit dem Namen my_data_defs.pyusing enthalten sein from my_data_defs import Fruits.
Martineau
24

Sie vergessen, es auch als binär zu lesen.

In Ihrem Schreibteil haben Sie:

open(b"Fruits.obj","wb") # Note the wb part (Write Binary)

Im gelesenen Teil haben Sie:

file = open("Fruits.obj",'r') # Note the r part, there should be a b too

Ersetzen Sie es also durch:

file = open("Fruits.obj",'rb')

Und es wird funktionieren :)


Der zweite Fehler ist höchstwahrscheinlich darauf zurückzuführen, dass die Datei nicht ordnungsgemäß geschlossen / synchronisiert wurde.

Versuchen Sie diesen Code, um zu schreiben:

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)
>>> filehandler.close()

Und dies (unverändert) zu lesen:

>>> import pickle
>>> file = open("Fruits.obj",'rb')
>>> object_file = pickle.load(file)

Eine sauberere Version würde die withAnweisung verwenden.

Zum Schreiben:

>>> import pickle
>>> with open('Fruits.obj', 'wb') as fp:
>>>     pickle.dump(banana, fp)

Zum Lesen:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)
Wolph
quelle
1
Ich verwende Ihre Version, die die with-Anweisung verwendet, und erhalte die folgende Meldung: Traceback (letzter Aufruf zuletzt): Datei "<pyshell # 20>", Zeile 1, in <module> print (banana.color) AttributeError: 'Fruits' Objekt hat kein Attribut 'Farbe'
Peterstone
17

In diesem Fall immer im Binärmodus geöffnet

file = open("Fruits.obj",'rb')
ismail
quelle
6

Sie haben die Datei nicht im Binärmodus geöffnet.

open("Fruits.obj",'rb')

Sollte arbeiten.

Bei Ihrem zweiten Fehler ist die Datei höchstwahrscheinlich leer, was bedeutet, dass Sie sie versehentlich geleert oder den falschen Dateinamen oder etwas anderes verwendet haben.

(Dies setzt voraus, dass Sie Ihre Sitzung wirklich geschlossen haben. Wenn nicht, liegt dies daran, dass Sie die Datei zwischen Schreiben und Lesen nicht geschlossen haben.)

Ich habe Ihren Code getestet und er funktioniert.

Lennart Regebro
quelle
3

Es scheint, dass Sie Ihre Klasseninstanzen über Sitzungen hinweg speichern möchten, und die Verwendung pickleist eine anständige Möglichkeit, dies zu tun. Es gibt jedoch ein Paket mit dem Namen klepto, das das Speichern von Objekten in einer Wörterbuchschnittstelle abstrahiert. Sie können also Objekte auswählen und in einer Datei speichern (siehe Abbildung unten) oder Objekte auswählen und in einer Datenbank speichern oder stattdessen Verwenden Sie Pickle Use Json oder viele andere Optionen. Das Schöne daran kleptoist, dass durch die Abstraktion zu einer gemeinsamen Benutzeroberfläche die Vereinfachung vereinfacht wird, sodass Sie sich nicht an die Details auf niedriger Ebene erinnern müssen, wie Sie durch Beizen in eine Datei oder auf andere Weise speichern können.

Beachten Sie, dass es für dynamisch hinzugefügte Klassenattribute funktioniert, was Pickle nicht kann ...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[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.
>>> from klepto.archives import file_archive 
>>> db = file_archive('fruits.txt')
>>> class Fruits: pass
... 
>>> banana = Fruits()
>>> banana.color = 'yellow'
>>> banana.value = 30
>>> 
>>> db['banana'] = banana 
>>> db.dump()
>>> 

Dann starten wir neu ...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[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.
>>> from klepto.archives import file_archive
>>> db = file_archive('fruits.txt')
>>> db.load()
>>> 
>>> db['banana'].color
'yellow'
>>> 

Klepto funktioniert auf python2 und python3.

Den Code erhalten Sie hier: https://github.com/uqfoundation

Mike McKerns
quelle
1

Sie können anycache verwenden , um die Arbeit für Sie zu erledigen. Angenommen, Sie haben eine Funktion, myfuncdie die Instanz erstellt:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc()
    banana = Fruits()
    banana.color = 'yellow'
    banana.value = 30
return banana

Anycache ruft myfuncbeim ersten Mal auf und nimmt das Ergebnis in eine Datei aufcachedir indem ein eindeutiger Bezeichner (abhängig vom Funktionsnamen und den Argumenten) als Dateiname verwendet wird. Bei jedem aufeinanderfolgenden Lauf wird das eingelegte Objekt geladen.

Wenn die cachedir zwischen Python-Läufen erhalten bleibt, wird das eingelegte Objekt aus dem vorherigen Python-Lauf übernommen.

Die Funktionsargumente werden ebenfalls berücksichtigt. Eine überarbeitete Implementierung funktioniert ebenfalls:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc(color, value)
    fruit = Fruits()
    fruit.color = color
    fruit.value = value
return fruit
c0fec0de
quelle