web-dev-qa-db-ja.com

複数のオブジェクトをpickleファイルに保存およびロードしますか?

私はゲームでプレイヤーにサービスを提供し、彼らと他のものを作成するクラスを持っています。

後で使用するには、これらのプレーヤーオブジェクトをファイルに保存する必要があります。 pickleモジュールを試しましたが、複数のオブジェクトを保存して再度ロードする方法がわかりませんか?それを行う方法はありますか、リストなどの他のクラスを使用して、オブジェクトをリストに保存およびロードする必要がありますか?

もっと良い方法はありますか?

52
Hamid FzM

これを行う最も一般的な方法は、リスト、タプル、または辞書を使用することです。

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']

ただし、ピクルファイルcanには任意の数のピクルが含まれます。同じ出力を生成するコードを次に示します。ただし、次のように記述して理解するのは難しいことに注意してください。

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

これを行う場合、書き出すファイルにいくつの漬物があるかを知る責任があります。上記のコードは、リストオブジェクトの数を最初にピクルすることでそれを行います。

60
Tim Peters

Tim Petersの受け入れられた答え への2つの追加。

最初に、ファイルの最後に達したときにロードを停止した場合、個別にピクルしたアイテムの数を保存する必要はありません:

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

items = loadall(myfilename)

これは、ファイルにピクルスのみが含まれていることを前提としています。そこに何か他のものがある場合、ジェネレーターはそこにあるものもピクルスとして扱いますが、これは危険です。

Second、この方法では、リストを取得するのではなく、 generator を取得します。これにより、一度に1つのアイテムのみがメモリにロードされます。これは、ダンプされたデータが非常に大きい場合に便利です。 itemsループを使用して、あたかもリストであるかのようにforを反復処理できます。

93
Lutz Prechelt

これを試して:

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()
10
N.S

pickleを使用してオブジェクト指向のデモを行い、1つまたは複数の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]
4
lyfing

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
>>>
0
Mike McKerns

繰り返しダンプする場合は、同様に繰り返し読む必要があります。

ループを実行できます受け入れられた答え が示すように)ファイルの終わりに到達するまで(その時点で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}]
0
cs95