views:

140

answers:

1

I would like to pickle an unbound method in Python 3.x. I'm getting this error:

>>> class A:
...     def m(self):
...         pass
>>> import pickle
>>> pickle.dumps(A.m)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    pickle.dumps(A.m)
  File "C:\Python31\lib\pickle.py", line 1358, in dumps
    Pickler(f, protocol, fix_imports=fix_imports).dump(obj)
_pickle.PicklingError: Can't pickle <class 'function'>: attribute lookup builtins.function failed

Does anyone have experience with this?


Note: In Python 2.x it's also impossible to pickle unbound methods by default; I managed to do it there in some weird way I don't understand: I wrote a reducer with the copy_reg module for the MethodType class, which covers both bound and unbound methods. But the reducer only solved the case of the bound method, because it depended on my_method.im_self. Mysteriously it has also caused Python 2.x to be able to pickle unbound methods. This does not happen on Python 3.x.

+1  A: 

This cannot be done directly because in Python 3 unbound method type is gone: it is just a function:

>>> print (type (A.m))
<class 'function'>

Python functions are not bound to a class, so it is impossible to tell what class A.m belongs to just by looking at the expression result.

Depending on what exactly you need, pickling/unpickling a tuple of (class, method-name) might be good enough:

>>> print (pickle.loads (pickle.dumps ((A, 'm'))))
... (<class '__main__.A'>, 'm')

You can get the method (function) from here simply by using getattr():

>>> cls, method = pickle.loads (pickle.dumps ((A, 'm')))
>>> print (getattr (cls, method))
... <function m at 0xb78878ec>
doublep
Are you saying that on Python 3, given an unbound method, there's no way of knowing where that method was defined?
cool-RR
Yes. Try declaring two classes and assign one method from one to another (`B.m = A.m`). Then `B.m` and `A.m` will be equal (in fact, identical), so it is not possible to tell whether you looked the method up in `B` or in `A`.
doublep