Сохранение и загрузка нескольких объектов в файл 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()
Другие вопросы по тегам