web-dev-qa-db-fra.com

Comment se décaper?

Je veux que ma classe implémente les fonctions Save and Load qui font simplement un pickle de la classe. Mais apparemment, vous ne pouvez pas utiliser le "soi" de la manière ci-dessous. Comment peux-tu faire ça?

self = cPickle.load(f)

cPickle.dump(self,f,2)
60
user317033

C'est ce que j'ai fini par faire. Mise à jour du __dict__ signifie que nous conservons toutes les nouvelles variables de membre que j'ajoute à la classe et que nous mettons simplement à jour celles qui étaient là lorsque l'objet a été pickle pour la dernière fois. Cela semble le plus simple tout en conservant le code de sauvegarde et de chargement à l'intérieur de la classe elle-même, donc appeler du code ne fait qu'un object.save ().

def load(self):
    f = open(self.filename, 'rb')
    tmp_dict = cPickle.load(f)
    f.close()          

    self.__dict__.update(tmp_dict) 


def save(self):
    f = open(self.filename, 'wb')
    cPickle.dump(self.__dict__, f, 2)
    f.close()
41
user317033

La partie de vidage devrait fonctionner comme vous l'avez suggéré. pour la partie chargement, vous pouvez définir un @ classmethod qui charge une instance à partir d'un fichier donné et la renvoie.

@classmethod
def loader(cls,f):
    return cPickle.load(f)

alors l'appelant ferait quelque chose comme:

class_instance = ClassName.loader(f)
20
Ofri Raviv

Si vous voulez que votre classe se mette à jour elle-même à partir d'un cornichon enregistré… vous devez à peu près utiliser __dict__.update, comme vous l'avez fait dans votre propre réponse. C'est un peu comme un chat poursuivant sa queue, cependant… comme vous demandez à l'instance de se "réinitialiser" essentiellement avec l'état antérieur.

Il y a un léger ajustement à votre réponse. Vous pouvez en fait pickle self.

>>> import dill
>>> class Thing(object):
...   def save(self):
...     return dill.dumps(self)
...   def load(self, obj):
...     self.__dict__.update(dill.loads(obj).__dict__)
... 
>>> t = Thing()
>>> t.x = 1
>>> _t = t.save()
>>> t.x = 2
>>> t.x
2
>>> t.load(_t)
>>> t.x
1

J'ai utilisé loads et dumps au lieu de load et dump parce que je voulais que le cornichon soit sauvegardé dans une chaîne. L'utilisation de load et dump dans un fichier fonctionne également. Et, en fait, je peux utiliser dill pour ramasser une instance de classe dans un fichier, pour une utilisation ultérieure… même si la classe est définie de manière interactive. Continuant d'en haut ...

>>> with open('self.pik', 'w') as f:
...   dill.dump(t, f)
... 
>>> 

puis arrêt et redémarrage ...

Python 2.7.10 (default, May 25 2015, 13:16:30) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> with open('self.pik', 'r') as f:
...   t = dill.load(f)
... 
>>> t.x
1
>>> print dill.source.getsource(t.__class__)
class Thing(object):
  def save(self):
    return dill.dumps(self)
  def load(self, obj):
    self.__dict__.update(dill.loads(obj).__dict__)

>>> 

J'utilise dill, qui est disponible ici: https://github.com/uqfoundation

8
Mike McKerns

Il y a un exemple de comment pickle une instance ici, dans la documentation . (Recherchez l'exemple "TextReader"). L'idée est de définir __getstate__ et __setstate__, qui vous permettent de définir quelles données doivent être picklées et comment utiliser ces données pour ré-instancier l'objet.

2
unutbu