Alex wrote: > I have a serious problem and I hope there is some solution. It is > easier to illustrate with a simple code: > > >>>>class Parent(object): > > __slots__=['A', 'B'] > def __init__(self, a, b): > self.A=a; self.B=b > def __getstate__(self): > return self.A, self.B > def __setstate__(self, tup): > self.A, self.B=tup > > > >>>>class Child(Parent): > > __slots__=['C',] > def __init__(self, c): > self.C=c > def __getstate__(self): > return self.C, > def __setstate__(self, tup): > self.C, =tup > > > >>>>obj=Child(1) >>>>obj.A=2 >>>>obj.B=3 >>>>obj.A > > 2 > >>>>obj.B > > 3 > >>>>obj.C > > 1 > >>>>objct.Z=4 > > > Traceback (most recent call last): > File "<pyshell#60>", line 1, in -toplevel- > objct.Z=4 > AttributeError: 'Child' object has no attribute 'Z' > > So far so good.. Object obj inherited attributes (A and B) from the > parent class and refuses to take any new ones. But look what happens > when I try to pickle and unpickle it: > > >>>>import cPickle >>>>File=open('test', 'w') >>>>cPickle.dump(obj, File) >>>>File.close() >>>> >>>>file1=open('test', 'r') >>>>objct=cPickle.load(file1) >>>>file1.close() >>>>objct.A > > > Traceback (most recent call last): > File "<pyshell#55>", line 1, in -toplevel- > objct.A > AttributeError: A > >>>>objct.C > > 1 > > Its own attribute (C) value is restored but the value of an inherited > attribute (A) is not. I tried pickling protocol 2, and module pickle > instead of cPickle, all with the same result. > > What can be done?! Or maybe nothing can be done? > > I would greatly appreciate an advice. A lot of code is written, but now > we have a need for pickling and unpickling objects and discovered this > problem. > You have explicitly told the objects' class definition to only store the C attribute as a part of the object state.
If you change the definition of child to: class Child(Parent): __slots__=['C',] def __init__(self, c): self.C=c def __getstate__(self): return self.A, self.B, self.C, def __setstate__(self, tup): self.A, self.B, self.C, =tup everything works as you expect. But I presume you want the subclass to require no knowledge of the superclass state? In that case you might consider rewriting Child as class Child(Parent): __slots__ = ['C'] # only tuples need trailing comma def __init__(self, c): self.C = c def __getstate__(self): return Parent.__getstate__(self) + (self.C, ) def __setstate__(self, t): self.C = t[-1] Parent.__setstate__(self, t[:-1]) This would work adequately. May I ask your use case for __slots__? I presume there is a specific reason why you can't just code the classes as class Parent(object): def __init__(self, a, b): self.A = a self.B = b class Child(Parent): def __init__(self, c): self.C = c since these definitions will pickle and unpickle perfectly. A couple of other notes: First, it's always safest to open pickle files in binary mode, as this will eliminate the chance of platform differences making a pickle written on one architecture or platform being unreadable by another. Secondly, it's usual to have the subclass explicitly call the superclass to initialize that portion of the instance. So it would be more typically Pythonic to write class Child(Parent): def __init__(self, c): Parent.__init__(self, a, b) self.C = c This allows you to pass the a and b values into the creator call in the following way: obj = Child(2, 3, 1) rather than explicitly setting attributes of the Child instance in line. If your inheritance patterns are complex you may find it useful to investigate the super() function. regards Steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC www.holdenweb.com PyCon TX 2006 www.python.org/pycon/ -- http://mail.python.org/mailman/listinfo/python-list