Reputation: 75
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?
Upvotes: 7
Views: 2779
Reputation: 75
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)
Upvotes: 0
Reputation: 906
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)
Upvotes: 3
Reputation: 35217
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
Upvotes: 8