Search code examples
pythonpickle

Python: Can't pickle type X, attribute lookup failed


I am trying to pickle a 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()

This produces the following output:

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

What am I doing wrong? Is the problem that Bar is a member of Foo? (Moving the definition of Bar to the top level solves the problem, although I'm still curious why this happens.)


Solution

  • Yes, the fact that it's a class member is a problem:

    >>> 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'>
    

    The problem is that when namedtuple() returns a type object, it isn't aware of the fact that it's being assigned to a class member - and thus, it tells the type object that its type name should be __main__.Bar, even though it should really be __main__.Foo.Bar.