Why can't you pickle instancemethods?

Chris chrisspen at gmail.com
Fri Oct 20 19:58:22 EDT 2006


mdsteele at gmail.com wrote:
> Chris wrote:
> > Why can pickle serialize references to functions, but not methods?
> >
> > Pickling a function serializes the function name, but pickling a
> > staticmethod, classmethod, or instancemethod generates an error. In
> > these cases, pickle knows the instance or class, and the method, so
> > what's the problem? Pickle doesn't serialize code objects, so why can't
> > it serialize the name as it does for functions? Is this one of those
> > features that's feasible, but not useful, so no one's ever gotten
> > around to implementing it?
>
> I have often wondered this myself.  I'm convinced that it would in fact
> be useful -- more than once I've written a program that has lots of
> objects with function pointers, and where it was inconvenient that the
> method pointers could not be pickled.  One compromise that I have used
> before is to write a class such as:
>
> class InstanceMethodSet(object):
>     def __init__(self,methods):
>         self.methods = set(methods)
>     def __getstate__(self):
>         return [(method.im_self, method.im_func.func_name)
>                 for method in self.method]
>     def __setstate__(self,state):
>         self.methods = set(getattr(obj,name) for obj,name in state)
>
> Obviously, this particular example is crude and not terribly robust,
> but it seems to do the job -- it effectively lets you pickle a set of
> instance method pointers.  I don't know of any reason why instance
> methods (or class or static methods) couldn't be pickled directly,
> unless perhaps there exists some kind of pathological corner case that
> would create Badness?
>
> -Matt

Thanks, that's quite clever. Although I think you'd still have to
explicitly specify im_self for staticmethods. I could imagine a similar
callable proxy that simply removes the direct method reference from the
equation:

class MethodProxy(object):
    def __init__(self, obj, method):
        self.obj = obj
        if isinstance(method, basestring):
            self.methodName = method
        else:
            assert callable(method)
            self.methodName = method.func_name
    def __call__(self, *args, **kwargs):
        return getattr(self.obj, self.methodName)(*args, **kwargs)

picklableMethod = MethodProxy(someObj, someObj.method)




More information about the Python-list mailing list