Сохранение и загрузка нескольких объектов в файл pickle?
У меня есть класс, который обслуживает игроков в игре, создает их и другие вещи.
Мне нужно сохранить эти объекты проигрывателя в файл, чтобы использовать его позже. Я пробовал модуль pickle, но я не знаю, как сохранить несколько объектов и снова загрузить их? Есть ли способ сделать это, или я должен использовать другие классы, такие как списки и сохранять и загружать мои объекты в списке?
Есть ли способ лучше?
8 ответов
Использование списка, кортежа или 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']
Однако файл маринада может содержать любое количество маринадов. Вот код, выдающий тот же результат. Но обратите внимание, что сложнее писать и понимать:
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
Если вы сделаете это, вы несете ответственность за то, чтобы знать, сколько солений содержится в файле, который вы записываете. Код выше делает это, сначала выбирая количество объектов списка.
Два дополнения к принятому ответу Тима Питерса.
Во-первых, вам не нужно хранить количество выбранных вами предметов отдельно, если вы остановите загрузку, когда дойдете до конца файла:
def loadall(filename):
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
items = loadall(myfilename)
Это предполагает, что файл содержит только соленые огурцы; если там есть что-то еще, генератор попытается обработать все остальное как соленые огурцы, что может быть опасно.
Во-вторых, таким образом, вы получаете не список, а генератор. Это позволит загружать в память только один элемент за раз, что полезно, если выгружаемые данные очень велики - одна из возможных причин, по которым вы, возможно, захотели сначала выбрать несколько элементов по отдельности. Вы все еще можете перебирать items
с for
цикл, как если бы это был список.
Попробуй это:
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()
Если вы сбрасываете его итеративно, вам также придется читать его итеративно.
Вы можете запустить цикл (как показывает принятый ответ), чтобы продолжать распаковывать строки, пока не дойдете до конца файла (в этот момент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}]
Я дам объектно-ориентированную демонстрацию, используя 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]
Предположим, мы сохранили объекты в файле класса Employee. Вот код для чтения всех объектов по одному из файла:
e = Employee()
with open(filename, 'rb') as a:
while True:
try:
e = pickle.load(a)
e.ShowRecord()
except EOFError:
break
Это легко, если вы используете klepto
, что дает вам возможность прозрачно хранить объекты в файлах или базах данных. Он использует dict API и позволяет вам 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
>>>
Вот как сбросить два (или более словарей) с помощью pickle и извлечь их обратно:
import pickle
dict_1 = {1: 'one', 2: 'two'}
dict_2 = {1: {1: 'one'}, 2: {2: 'two'}}
F = open('data_file1.pkl', 'wb')
pickle.dump(dict_1, F)
pickle.dump(dict_2, F)
F.close()
=========================================
import pickle
dict_1 = {1: 'one', 2: 'two'}
dict_2 = {1: {1: 'one'}, 2: {2: 'two'}}
F = open('data_file1.pkl', 'rb')
G = pickle.load(F)
print(G)
H = pickle.load(F)
print(H)
F.close()