The pickle documentation states that "when class instances are pickled, their class’s data are not pickled along with them. Only the instance data are pickled." Can anyone provide a recipe for including class variables as well as instance variables when pickling and unpickling?
Asked
Active
Viewed 2,367 times
3 Answers
8
Use dill
instead of pickle, and code exactly how you probably have done already.
>>> class A(object):
... y = 1
... x = 0
... def __call__(self, x):
... self.x = x
... return self.x + self.y
...
>>> b = A()
>>> b.y = 4
>>> b(2)
6
>>> b.z = 5
>>> import dill
>>> _b = dill.dumps(b)
>>> b_ = dill.loads(_b)
>>>
>>> b_.z
5
>>> b_.x
2
>>> b_.y
4
>>>
>>> A.y = 100
>>> c = A()
>>> _c = dill.dumps(c)
>>> c_ = dill.loads(_c)
>>> c_.y
100

Mike McKerns
- 33,715
- 8
- 119
- 139
-
This looks like an excellent solution, thank you! I'll upvote you as soon as I'm able. – rmodrak Oct 16 '14 at 22:00
-
I'm curious though, can anyone provide an alternative solution using only standard library functions? – rmodrak Oct 16 '14 at 22:01
-
Yes, `dill` just uses `copy_reg`, `save_reduce`, and `save_global` under the covers, so you could do the same… it'd just be more work on your part. – Mike McKerns Oct 16 '14 at 22:07
0
You can do this easily using the standard library functions by using __getstate__
and __setstate__
:
class A(object):
y = 1
x = 0
def __getstate__(self):
ret = self.__dict__.copy()
ret['cls_x'] = A.x
ret['cls_y'] = A.y
return ret
def __setstate__(self, state):
A.x = state.pop('cls_x')
A.y = state.pop('cls_y')
self.__dict__.update(state)

Richard Whitehead
- 749
- 8
- 14
0
Here's a solution using only standard library modules. Simply execute the following code block, and from then on pickle behaves in the desired way. As Mike McKerns was saying, dill
does something similar under the hood.
Based on relevant discussion found here.
import copy_reg
def _pickle_method(method):
func_name = method.im_func.__name__
obj = method.im_self
cls = method.im_class
return _unpickle_method, (func_name, obj, cls)
def _unpickle_method(func_name, obj, cls):
for cls in cls.mro():
try:
func = cls.__dict__[func_name]
except KeyError:
pass
else:
break
return func.__get__(obj, cls)
copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)

rmodrak
- 65
- 6