Сохранение и загрузка нескольких объектов в файле pickle?
У меня есть класс, который обслуживает игроков в игре, создает их и другие вещи.
Мне нужно сохранить эти объекты проигрывателя в файл, чтобы использовать его позже. Я пробовал модуль pickle, но я не знаю, как сохранить несколько объектов и снова загрузить их? Есть ли способ сделать это, или я должен использовать другие классы, такие как списки и сохранять и загружать мои объекты в списке?
Есть ли способ лучше?
Ответы
Ответ 1
Использование списка, кортежа или dict - наиболее распространенный способ сделать это:
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)
Что печатает:
['A', 'b', 'C', 'd']
Однако файл pickle может содержать любое количество соленья. Здесь код производит тот же вывод. Но обратите внимание, что сложнее писать и понимать:
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
Если вы это сделаете, вы несете ответственность за знание того, сколько соленья находится в файле, который вы выписываете. Вышеприведенный код делает это, сначала пробивая количество объектов списка.
Ответ 2
Два дополнения к принятому ответу Тима Питерса.
Во-первых, вам не нужно хранить количество выбранных вами предметов отдельно, если вы остановите загрузку, когда дойдете до конца файла:
def loadall(filename):
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
items = loadall(myfilename)
Это предполагает, что файл содержит только соленые огурцы; если там есть что-то еще, генератор попытается обработать все остальное как огурцы, что может быть опасно.
Во-вторых, таким образом, вы получаете не список, а генератор. Это позволит загружать в память только один элемент за раз, что полезно, если выгружаемые данные очень велики - одна из возможных причин, по которым вы, возможно, захотели сначала выбрать несколько элементов по отдельности. Вы все еще можете перебирать items
с циклом for
как если бы это был список.
Ответ 3
Попробуй это:
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()
Ответ 4
Я дам объектно-ориентированную демонстрацию с помощью pickle
для хранения и восстановления одного или нескольких object
:
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
выход:
item: [<Worker> name:tom1 addr:China]
item-list: [<Worker> name:tom2 addr:China]
item-list: [<Worker> name:tom3 addr:China]
Ответ 5
Это легко, если вы используете klepto
, что дает вам возможность прозрачно хранить объекты в файлах или базах данных. Он использует API-интерфейс dict и позволяет вам делать dump
и/или load
определенные записи из архива (в следующем случае сериализованные объекты сохраняют одну запись на файл в каталоге с именем 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
>>>
Ответ 6
Если вы дампируете его итеративно, вам придется читать его итеративно.
Вы можете запустить цикл (как показано в принятом ответе), чтобы не допускать сортировку строк до тех пор, пока не достигнете конца файла (после чего возникает EOFError
).
data = []
with open("data.pickle", "rb") as f:
while True:
try:
data.append(pickle.load(f))
except EOFError:
break
Минимальный проверяемый пример
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
Конечно, это при условии, что ваши объекты должны быть протравлены индивидуально. Вы также можете сохранить свои данные в виде единого списка объектов, а затем использовать один вызов pickle/unpickle (нет необходимости в циклах).
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}]