Python: no se puede encoger tipo X, error en la búsqueda de atributos

Estoy tratando de namedtuple una 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 __name__ == '__main__': f = Foo() f.baz() 

Esto produce el siguiente resultado:

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

¿Qué estoy haciendo mal? ¿Es el problema que Bar es miembro de Foo ? (Mover la definición de Bar al nivel superior resuelve el problema, aunque todavía siento curiosidad por lo que ocurre).

Sí, el hecho de que sea un miembro de la clase es un problema:

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

El problema es que cuando namedtuple() devuelve un objeto de tipo, no es consciente del hecho de que se está asignando a un miembro de la clase y, por lo tanto, le dice al objeto de tipo que su nombre de tipo debe ser __main__.Bar , aunque realmente debería ser __main__.Foo.Bar .

Las clases anidadas hacen que el pickle falle, ya que depende de la ruta del objeto dentro de la aplicación para reconstruirlo más tarde.

La solución inmediata es no anidar clases, es decir, mover la definición de la Bar a Foo fuera. El código funcionará igual.

Pero una cosa mejor que hacer es no utilizar pickle en absoluto para almacenar datos. Utilice algún otro formato de serialización, como json , o una base de datos, como sqlite3 .

Acaba de llegar a uno de los muchos inconvenientes de pickle: si cambia su código, mueve las cosas o, a veces, realiza pequeños cambios estructurales, sus datos se vuelven no descargables.

Además de eso, el pickle tiene otras desventajas: es lento, inseguro, solo en python …

El uso de eneldo en lugar de pickle aquí permitirá que esto funcione