it-swarm.com.de

Speichern und Laden mehrerer Objekte in einer Pickle-Datei?

Ich habe eine Klasse, die den Spielern in einem Spiel dient, sie erstellt und andere Dinge. 

Ich muss diese Playerobjekte in einer Datei speichern, um sie später verwenden zu können. Ich habe das Pickle-Modul ausprobiert, weiß aber nicht, wie ich mehrere Objekte speichern und erneut laden kann. Gibt es eine Möglichkeit, dies zu tun, oder sollte ich andere Klassen wie Listen verwenden und meine Objekte in einer Liste speichern und laden? 

Gibt es einen besseren Weg?

41
Hamid FzM

Die Verwendung einer Liste, eines Tupels oder eines Diktiers ist bei weitem die gebräuchlichste Methode, dies zu tun:

import pickle
PIK = "pickle.dat"

data = ["A", "b", "C", "d"]
with open(PIK, "wb") as f:
    pickle.dump(data, f)
with open(PIK, "rb") as f:
    print pickle.load(f)

Das druckt:

['A', 'b', 'C', 'd']

Eine Pickle-Datei kann kann jedoch eine beliebige Anzahl von Pickles enthalten. Hier ist der Code, der dieselbe Ausgabe erzeugt. Beachten Sie jedoch, dass es schwieriger ist, zu schreiben und zu verstehen:

with open(PIK, "wb") as f:
    pickle.dump(len(data), f)
    for value in data:
        pickle.dump(value, f)
data2 = []
with open(PIK, "rb") as f:
    for _ in range(pickle.load(f)):
        data2.append(pickle.load(f))
print data2

Wenn Sie dies tun, sind Sie dafür verantwortlich zu wissen, wie viele Pickles sich in der Datei befinden, die Sie schreiben. Der obige Code tut dies, indem zuerst die Anzahl der Listenobjekte ausgewählt wird.

47
Tim Peters

Zwei Ergänzungen zu Tim Peters 'akzeptierter Antwort .

Zuerst müssen Sie die Anzahl der Elemente, die Sie ausgewählt haben, nicht separat speichern, wenn Sie den Ladevorgang am Ende der Datei beenden:

def loadall(filename):
    with open(filename, "rb") as f:
        while True:
            try:
                yield pickle.load(f)
            except EOFError:
                break

items = loadall(myfilename)

Es wird davon ausgegangen, dass die Datei nur Pickles enthält. Wenn sonst noch etwas drin ist, wird der Generator versuchen, alles andere auch als Pickles zu behandeln, was gefährlich werden kann.

Second, auf diese Weise erhalten Sie keine Liste, sondern einen Generator . Dadurch wird jeweils nur ein Element in den Speicher geladen. Dies ist nützlich .__ sehr groß - ein möglicher Grund, warum Sie .__ mehrere Objekte zunächst separat auswählen wollten . Sie können items immer noch mit einer for-Schleife wiederholen, als wäre es eine.

82
Lutz Prechelt

Versuche dies:

import pickle

file = open('test.pkl','wb')
obj_1 = ['test_1', {'ability', 'mobility'}]
obj_2 = ['test_2', {'ability', 'mobility'}]
obj_3 = ['test_3', {'ability', 'mobility'}]

pickle.dump(obj_1, file)
pickle.dump(obj_2, file)
pickle.dump(obj_3, file)

file.close()

file = open('test.pkl', 'rb')
obj_1 = pickle.load(file)
obj_2 = pickle.load(file)
obj_3 = pickle.load(file)
print(obj_1)
print(obj_2)
print(obj_3)
file.close()
9
N.S

Ich gebe eine objektorientierte Demo mit pickle, um eine oder mehrere object zu speichern und wiederherzustellen:

class Worker(object):

    def __init__(self, name, addr):
        self.name = name
        self.addr = addr

    def __str__(self):
        string = u'[<Worker> name:%s addr:%s]' %(self.name, self.addr)
        return string

# output one item
with open('testfile.bin', 'wb') as f:
    w1 = Worker('tom1', 'China')
    pickle.dump(w1, f)

# input one item
with open('testfile.bin', 'rb') as f:
    w1_restore = pickle.load(f)
print 'item: %s' %w1_restore

# output multi items
with open('testfile.bin', 'wb') as f:
    w1 = Worker('tom2', 'China')
    w2 = Worker('tom3', 'China')
    pickle.dump([w1, w2], f)

# input multi items
with open('testfile.bin', 'rb') as f:
    w_list = pickle.load(f)

for w in w_list:
    print 'item-list: %s' %w

ausgabe:

item: [<Worker> name:tom1 addr:China]
item-list: [<Worker> name:tom2 addr:China]
item-list: [<Worker> name:tom3 addr:China]
3
lyfing

Wenn Sie klepto verwenden, ist es einfach, Objekte in Dateien oder Datenbanken transparent zu speichern. Es verwendet eine Dict-API und ermöglicht es Ihnen, dump- und/oder load-spezifische Einträge aus einem Archiv (in dem Fall unten serialisierte Objekte einen Eintrag pro Datei in einem Verzeichnis mit dem Namen scores).

>>> import klepto
>>> scores = klepto.archives.dir_archive('scores', serialized=True)
>>> scores['Guido'] = 69 
>>> scores['Fernando'] = 42
>>> scores['Polly'] = 101
>>> scores.dump()
>>> # access the archive, and load only one 
>>> results = klepto.archives.dir_archive('scores', serialized=True)
>>> results.load('Polly')
>>> results
dir_archive('scores', {'Polly': 101}, cached=True)
>>> results['Polly']
101
>>> # load all the scores
>>> results.load()
>>> results['Guido']
69
>>>
0
Mike McKerns

Wenn Sie es iterativ ausgeben, müssen Sie es auch iterativ lesen.

Sie können eine Schleife (wie die akzeptierte Antwort zeigt) ausführen, um das Beizen von Zeilen zu vermeiden bis Sie das Dateiende erreichen (an diesem Punkt wird ein EOFError ausgelöst).

data = []
with open("data.pickle", "rb") as f:
    while True:
        try:
            data.append(pickle.load(f))
        except EOFError:
            break

Minimal verifizierbares Beispiel

import pickle

# Dumping step
data = [{'a': 1}, {'b': 2}]
with open('test.pkl', 'wb') as f:
    for d in data:
        pickle.dump(d, f)

# Loading step
data2 = []
with open('test.pkl', 'rb') as f:
    while True:
        try:
            data2.append(pickle.load(f))
        except EOFError:
            break

data2
# [{'a': 1}, {'b': 2}]

data == data2
# True

Dies setzt natürlich voraus, dass Ihre Objekte einzeln gebeizt werden müssen. Sie können Ihre Daten auch als einzelne Objektliste speichern und dann verwenden ein einzelner Pickle/Unpickle-Aufruf (keine Notwendigkeit für Schleifen).

data = [{'a':1}, {'b':2}]  # list of dicts as an example
with open('test.pkl', 'wb') as f:
    pickle.dump(data, f)

with open('test.pkl', 'rb') as f:
    data2 = pickle.load(f)

data2
# [{'a': 1}, {'b': 2}]
0
cs95