我有一堂课,为游戏中的玩家提供服务,创建他们以及其他东西。
我需要将这些播放器对象保存在文件中,以便以后使用。我已经尝试过pickle模块,但是我不知道如何保存多个对象并再次加载它们?有没有办法做到这一点,还是应该使用其他类(例如列表)并将对象保存并加载到列表中?
有没有更好的办法?
我有一堂课,为游戏中的玩家提供服务,创建他们以及其他东西。
我需要将这些播放器对象保存在文件中,以便以后使用。我已经尝试过pickle模块,但是我不知道如何保存多个对象并再次加载它们?有没有办法做到这一点,还是应该使用其他类(例如列表)并将对象保存并加载到列表中?
有没有更好的办法?
Answers:
到目前为止,使用列表,元组或字典是最常见的方法:
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
循环就好像它是一个列表。
load(myfilename)
在迭代结果之前,调用实际上不会加载数据或从文件中读取数据。如果要立即加载它们,请使用list(load(myfilename))
或for
循环之类的方法。
yield
外面的with open()
块?允许这样做会导致不必要的读取来遍历pickle文件,但我认为我宁愿使用它来悬挂文件句柄。除非我们确定此方法始终会迅速被EOF调用,否则我们将在到达文件末尾时关闭文件。(但是,如果我们不愿意产生单个元素,那可能是因为我们不需要解开文件中的所有对象。)
with open
它将终止并正确关闭文件。如果它可能用不完,我们通常不会在意打开的文件。如果它可能没有被使用到最后并且我们不喜欢打开的文件,那么是的,上面的构造并不是最好的方法。
尝试这个:
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()
我将提供一个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]
如果要迭代转储,则还必须迭代读取。
您可以运行一个循环(如已接受的答案所示),以保持不分批处理行,直到到达文件末尾(此时EOFError
引发an )。
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}]
如果使用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
>>>
以下是使用泡菜转储两个(或更多字典)并将其提取回去的方法:
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()
假设我们已将对象保存在Employee类的文件中。这是读取文件中所有对象的代码:
e = Employee()
with open(filename, 'rb') as a:
while True:
try:
e = pickle.load(a)
e.ShowRecord()
except EOFError:
break
list
集装箱似乎是合理的。