web-dev-qa-db-fra.com

Enregistrement et chargement de plusieurs objets dans un fichier pickle?

J'ai une classe qui sert les joueurs dans un jeu, les crée et d'autres choses. 

J'ai besoin de sauvegarder ces objets de joueur dans un fichier pour pouvoir l'utiliser plus tard. J'ai essayé le module pickle mais je ne sais pas comment enregistrer plusieurs objets et les charger à nouveau? Y at-il un moyen de faire cela ou devrais-je utiliser d'autres classes telles que des listes et enregistrer et charger mes objets dans une liste? 

Y a-t-il un meilleur moyen?

41
Hamid FzM

Utiliser une liste, un tuple ou un dict est de loin le moyen le plus courant de le faire:

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)

Cela imprime:

['A', 'b', 'C', 'd']

Cependant, un fichier de cornichons can contient un nombre quelconque de cornichons. Voici du code produisant la même sortie. Mais notez qu'il est plus difficile d'écrire et de comprendre:

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

Si vous faites cela, vous êtes responsable de savoir combien de cornichons sont dans le fichier que vous écrivez. Le code ci-dessus le fait en choisissant d'abord le nombre d'objets de la liste.

47
Tim Peters

Deux ajouts à La réponse acceptée de Tim Peters .

First, vous n’avez pas besoin de stocker le nombre d’articles que vous avez décapés séparément si vous arrêtez de charger lorsque vous cliquez sur la fin du fichier:

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

items = loadall(myfilename)

Cela suppose que le fichier ne contient que des cornichons; S'il y a autre chose à l'intérieur, le générateur essaiera de traiter tout ce qui s'y trouve comme des cornichons, ce qui pourrait être dangereux.

Second, de cette façon, vous n’obtenez pas une liste mais un générateur . Ceci ne chargera qu’un seul élément en mémoire à la fois, ce qui est utile très grand - une des raisons possibles pour lesquelles vous pourriez avoir eu l'intention de traiter plusieurs éléments séparément en premier lieu ... vous pouvez toujours parcourir items avec une boucle for comme s'il s'agissait d'une liste.

82
Lutz Prechelt

Essaye ça:

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

Je vais donner une démo orientée objet en utilisant pickle pour stocker et restaurer une ou plusieurs 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

sortie:

item: [<Worker> name:tom1 addr:China]
item-list: [<Worker> name:tom2 addr:China]
item-list: [<Worker> name:tom3 addr:China]
3
lyfing

C'est facile si vous utilisez klepto, qui vous permet de stocker des objets de manière transparente dans des fichiers ou des bases de données. Il utilise une API dict et vous permet de dump et/ou load entrées spécifiques d'une archive (dans le cas ci-dessous, les objets sérialisés stockaient une entrée par fichier dans un répertoire appelé 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