2010-02-05 5 views
24

J'essaie de décaper un objet d'une classe I (nouveau style) définie. Mais je reçois l'erreur suivante:Pourquoi ai-je une erreur sur ma classe définissant __slots__ en essayant de décaper un objet?

>>> with open('temp/connection.pickle','w') as f: 
... pickle.dump(c,f) 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/usr/lib/python2.5/pickle.py", line 1362, in dump 
    Pickler(file, protocol).dump(obj) 
    File "/usr/lib/python2.5/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/usr/lib/python2.5/pickle.py", line 331, in save 
    self.save_reduce(obj=obj, *rv) 
    File "/usr/lib/python2.5/pickle.py", line 419, in save_reduce 
    save(state) 
    File "/usr/lib/python2.5/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/usr/lib/python2.5/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems 
    save(v) 
    File "/usr/lib/python2.5/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/usr/lib/python2.5/copy_reg.py", line 76, in _reduce_ex 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 

Je ne définissaient pas explicitement __slots__ dans ma classe. Est-ce que quelque chose que je fais implicitement le définir? Comment est-ce que je travaille autour de ceci? Ai-je besoin de définir __getstate__?

Mise à jour:gnibbler a choisi un bon exemple. La classe de l'objet que j'essaie de décaper enveloppe une douille. (Il me semble maintenant que) les sockets définissent __slots__ et non __getstate__ pour une bonne raison. Je suppose qu'une fois qu'un processus se termine, un autre processus ne peut pas se décomposer et utiliser la connexion socket du processus précédent. Donc, alors que j'accepte l'excellente réponse de Alex Martelli, je vais devoir poursuivre une stratégie différente de celle du décapage pour «partager» la référence de l'objet.

+1

Pouvez-vous montrer du code de la classe? Nous n'avons probablement pas besoin de voir * toutes * les méthodes. –

Répondre

26

La classe définissant __slots__ (et non __getstate__) peut être soit une classe d'ancêtres, soit une classe (ou une classe d'ancêtres) d'un attribut ou d'un élément de la vôtre, directement ou indirectement: essentiellement, la classe de tout objet dans le a orienté le graphique de références avec votre objet en tant que root, puisque le décapage doit sauvegarder le graphique entier.

Une solution simple à votre dilemme est d'utiliser le protocole -1, ce qui signifie que "le meilleur pickle de protocole peut utiliser"; la valeur par défaut est un ancien protocole ASCII qui impose cette limitation à environ __slots__ par rapport à __getstate__. Tenir compte:

>>> class sic(object): 
... __slots__ = 'a', 'b' 
... 
>>> import pickle 
>>> pickle.dumps(sic(), -1) 
'\x80\x02c__main__\nsic\nq\x00)\x81q\x01.' 
>>> pickle.dumps(sic()) 
Traceback (most recent call last): 
    [snip snip] 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 
>>> 

Comme vous le voyez, le protocole -1 prend la __slots__ dans la foulée, alors que le protocole par défaut donne la même exception que vous avez vu.

Les problèmes avec le protocole -1: il produit une chaîne binaire/fichier, plutôt qu'un ASCII comme le protocole par défaut; le fichier mariné résultant ne serait pas chargeable par des versions suffisamment anciennes de Python. Avantages, en plus de la clé par rapport à __slots__, comprennent des résultats plus compacts, et de meilleures performances.

Si vous êtes obligé d'utiliser le protocole par défaut, vous devrez identifier exactement quelle classe vous pose problème et pourquoi exactement. Nous pouvons discuter des stratégies si c'est le cas (mais si vous pouvez éventuellement utiliser le protocole -1, c'est tellement mieux que ça ne vaut pas la peine de discuter ;-) et une simple inspection de code à la recherche de la classe/objet problématique s'avère trop compliquée (j'ai en gardant à l'esprit certaines astuces basées sur la deepcopy pour obtenir une représentation utilisable de l'ensemble du graphique, au cas où vous vous poseriez la question).

2

De PEP 307:

The __getstate__ method should return a picklable value representing the object's state without referencing the object itself. If no __getstate__ method exists, a default implementation is used that returns self.__dict__ .

6

Peut-être un attribut de votre instance utilise __slots__

Par exemple, socket a __slots__ ne peut donc pas être décapée

Vous devez identifier quel attribut provoque l'erreur et écrit la vôtre __getstate__ et __setstate__ pour ignorer cet attribut

Questions connexes