web-dev-qa-db-fra.com

Python: impossible de décaper le type X, la recherche d'attribut a échoué

J'essaye de mariner un namedtuple:

from collections import namedtuple
import cPickle

class Foo:

    Bar = namedtuple('Bar', ['x', 'y'])

    def baz(self):
        s = set()
        s.add(Foo.Bar(x=2, y=3))
        print cPickle.dumps(s)

if __== '__main__':
    f = Foo()
    f.baz()

Cela produit la sortie suivante:

Traceback (most recent call last):
  File "scratch.py", line 15, in <module>
    f.baz()
  File "scratch.py", line 11, in baz
    print cPickle.dumps(s)
cPickle.PicklingError: Can't pickle <class '__main__.Bar'>: attribute lookup __main__.Bar failed

Qu'est-ce que je fais mal? Le problème est-il que Bar est membre de Foo? (Déplacer la définition de Bar au niveau supérieur résout le problème, même si je suis toujours curieux de savoir pourquoi cela se produit.)

40
Nick Heiner

Oui, le fait que ce soit un membre de la classe est un problème:

>>> class Foo():
...     Bar = namedtuple('Bar', ['x','y'])
...     def baz(self):
...         b = Foo.Bar(x=2, y=3)
...         print(type(b))
...
>>> a = Foo()
>>> a.baz()
<class '__main__.Bar'>

Le problème est que lorsque namedtuple() renvoie un objet type, il n'est pas conscient du fait qu'il est affecté à un membre de classe - et donc, il indique à l'objet type que son nom de type doit être __main__.Bar, Même si cela devrait vraiment être __main__.Foo.Bar.

29
Amber

L'imbrication des classes fait échouer le cornichon, car il s'appuie sur le chemin de l'objet à l'intérieur de votre application pour le reconstruire plus tard.

La solution immédiate consiste à ne pas imbriquer les classes, c'est-à-dire à déplacer la définition Bar vers l'extérieur Foo. Le code fonctionnera tout de même.

Mais une meilleure chose à faire est de ne pas utiliserpickle pour stocker des données. Utilisez un autre format de sérialisation, comme json, ou une base de données, comme sqlite3.

Vous venez de frapper l'un des nombreux inconvénients du cornichon, si vous changez votre code, déplacez des choses ou faites parfois de petits changements structurels, vos données deviennent déchargeables.

En plus de cela, le cornichon a d'autres inconvénients: il est lent, non sécurisé, uniquement en python ...

13
nosklo

L'utilisation d'aneth à la place du cornichon ici permettra à cela de fonctionner

7
Maximilian