web-dev-qa-db-fra.com

Pickle avec des classes personnalisées

Supposons que j'ai une simple définition de classe python dans un fichier myClass.py

class Test:
    A = []

Et j'ai aussi deux scripts de test. Le premier script crée un objet de type Test, remplit le tableau A et décapage le résultat dans un fichier. Il le décompresse immédiatement du fichier et le tableau est toujours rempli. Le deuxième script se détache simplement du fichier, et le tableau n'est pas rempli (c'est-à-dire A == []). Pourquoi est-ce?

test1.py

import myClass
import pickle

x = myClass.Test()

for i in xrange(5):
    x.A.append(i)

f = open('data', 'w')
pickle.dump(x,f)
f.close()

f = open('data')
y = pickle.load(f)
f.close

print y.A

et test2.py

import myClass
import pickle

f = open('data')
y = pickle.load(f)
f.close

print y.A
23
Joe

C'est parce que vous définissez Test.A comme attribut de classe au lieu d'un attribut d'instance. Ce qui se passe vraiment, c'est qu'avec test1.py, l'objet lu à partir du fichier pickle est le même que test2.py, mais il utilise la classe en mémoire où vous aviez initialement assigné x.A.

Lorsque vos données sont extraites du fichier, elles créent une nouvelle instance du type de classe, puis appliquent toutes les données d'instance dont elles ont besoin. Mais vos seules données étaient un attribut de classe. Cela renvoie toujours à la classe qui est en mémoire, que vous avez modifiée dans un, mais pas dans un autre fichier.

Comparez les différences dans cet exemple:

class Test:
    A = []  # a class attribute
    def __init__(self):
        self.a = []  # an instance attribute

Vous remarquerez que l'attribut d'instance a sera correctement décapé et décapé, tandis que l'attribut de classe A fera simplement référence à la classe en mémoire.

for i in xrange(5):
    x.A.append(i)
    x.a.append(i)  

with open('data', 'w') as f:
    pickle.dump(x,f)

with open('data') as f:
    y = pickle.load(f)

>>> y.A
[0, 1, 2, 3, 4]
>>> y.a
[0, 1, 2, 3, 4]
>>> Test.A
[0, 1, 2, 3, 4]
>>> Test.A = []  # resetting the class attribute
>>> y.a 
[0, 1, 2, 3, 4]
>>> y.A  # refers to the class attribute
[]
30
jdi

C'est une vieille question, si vous la voyez maintenant, vous voulez probablement définir __getstate__ et __setstate__ de votre classe pour que pickle sache comment vider et charger votre classe définie.

Voir exemples ici.

Si votre classe est simple (par exemple, ne compte que des entrées et des chaînes comme membres et n'importe quelle méthode), elle devrait être sélectionnable automatiquement.

0
borgr