views:

217

answers:

4

I have a nested class:

class WidgetType(object):

    class FloatType(object):
        pass

    class TextType(object):
        pass

.. and an oject that refers the nested class type (not an instance of it) like this

class ObjectToPickle(object):
     def __init__(self):
         self.type = WidgetType.TextType

Trying to serialize an instance of the ObjectToPickle class results in:

*PicklingError: Can't pickle <class 'setmanager.app.site.widget_data_types.TextType'>*

Is there a way to pickle nested classes in python?

A: 

Pickle only works with classes defined in module scope (top level). In this case, it looks like you could define the nested classes in module scope and then set them as properties on WidgetType, assuming there's a reason not to just reference TextType and FloatType in your code. Or, import the module they're in and use widget_type.TextType and widget_type.FloatType.

Jason S
[..]set them as properties on WidgetType[..]Doing so yields:"TypeError: can't pickle property objects"
prinzdezibel
+2  A: 

The pickle module is trying to get the TextType class from the module. But since the class is nested it doesn't work. jasonjs's suggestion will work. Here are the lines in pickle.py responsible for the error message:

    try:
        __import__(module)
        mod = sys.modules[module]
        klass = getattr(mod, name)
    except (ImportError, KeyError, AttributeError):
        raise PicklingError(
            "Can't pickle %r: it's not found as %s.%s" %
            (obj, module, name))

klass = getattr(mod, name) will not work in the nested class case of course. To demonstrate what is going on try to add these lines before pickling the instance:

import sys
setattr(sys.modules[__name__], 'TextType', WidgetType.TextType)

This code adds TextType as an attribute to the module. The pickling should work just fine. I don't advice you to use this hack though.

Nadia Alramli
A: 

Nadia's answer is pretty complete - it is practically not something you want to be doing; are you sure you can't use inheritance in WidgetTypes instead of nested classes?

The only reason to use nested classes is to encapsulate classes working together closely, your specific example looks like an immediate inheritance candidate to me - there is no benefit in nesting WidgetType classes together; put them in a module and inherit from the base WidgetType instead.

kibitzer
+1  A: 

In sage [www.sagemath.org] we have a lot in instance of this pickling issues. The way we decide to systematically solve it is to put the outer class inside a specific metaclass whose goal is to implement and hide the hack. Note that this automatically propagate through nested classes if there are several level of nesting. Please see [http://trac.sagemath.org/sage_trac/browser/sage/misc/nested_class.py] for the code.

Hope it helps.

Hivert