How can I modify the classes below to make them pickeable?
This question: How to make a class which has __getattr__ properly pickable? is similar but refer to wrong exception in the use of getattr.
This other question seems to provide meaningful insight Why does pickle.dumps call __getattr__?, however it fails to provide an example, and I honestly cannot understand what I am suppose to implement.
import pickle
class Foo(object):
def __init__(self, dct):
for key in dct:
setattr(self, key, dct[key])
class Bar(object):
def __init__(self, dct):
for key in dct:
setattr(self, key, dct[key])
def __getattr__(self, attr):
"""If attr is not in channel, look in timing_data
"""
return getattr(self.foo, attr)
if __name__=='__main__':
dct={'a':1,'b':2,'c':3}
foo=Foo(dct)
dct2={'d':1,'e':2,'f':3,'foo':foo}
bar=Bar(dct2)
pickle.dump(bar,open('test.pkl','w'))
bar=pickle.load(open('test.pkl','r'))
Results:
14 """If attr is not in channel, look in timing_data
15 """
---> 16 return getattr(self.foo, attr)
17
18 if __name__=='__main__':
RuntimeError: maximum recursion depth exceeded while calling a Python object
The problem here is that your
__getattr__
method is poorly implemented. It assumes thatself.foo
exists. Ifself.foo
doesn't exist, trying to access it ends up calling__getattr__
- which results in infinite recursion:To fix this, you have to throw an AttributeError if no
foo
attribute exists:(I used the
vars
function to get the object's dict, because it looks nicer thanself.__dict__
.)Now everything works as expected: