Bug in Pickle protocol involving __setstate__

If we have a hierarchy of classes, and we use __getstate__/__setstate__, the wrong version of __setstate__ gets called. Possibly, this is a documentation problem, but here goes: Take two classes, A and B, where B is the child of A. Construct a B. Pickle it. Unpickle it, and you find that the __setstate__ function for A is called with the result produced by B.__getstate__(). This is wrong. An example follows: import pickle as P class A(object): def __init__(self, a): print 'A.__init__' self.a = a def __getstate__(self): print 'A.__getstate' return self.a def __setstate__(self, upstate): print 'A.__setstate', upstate self.a = upstate class B(A): def __init__(self, a, b): print 'B.__init__' A.__init__(self, a) self.b = b def __getstate__(self): print 'B.__getstate' return (A.__getstate__(self), self.b) def __setstate(self, upstate): # This never gets called! print 'B.__setstate', upstate A.__setstate__(self, upstate[0]) self.b = upstate[1] def __repr__(self): return '<B a=%d b=%d>' % (self.a, self.b) q = B(1,2) print '---' r = P.loads(P.dumps(q, 0)) print 'q=', q print 'r=', r Now, run it: $ python foo.py B.__init__ A.__init__ --- B.__getstate A.__getstate A.__setstate (1, 2) q= <B a=1 b=2, h=46912504218064> r= Traceback (most recent call last): File "foo.py", line 44, in <module> print 'r=', r File "foo.py", line 37, in __repr__ return '<B a=%d b=%d>' % (self.a, self.b) AttributeError: 'B' object has no attribute 'b' $

On Mon, Mar 3, 2008 at 8:00 AM, Greg Kochanski <greg.kochanski@phon.ox.ac.uk> wrote:
If we have a hierarchy of classes, and we use __getstate__/__setstate__, the wrong version of __setstate__ gets called.
Possibly, this is a documentation problem, but here goes:
No, it's a typo error :)
Take two classes, A and B, where B is the child of A.
Construct a B. Pickle it. Unpickle it, and you find that the __setstate__ function for A is called with the result produced by B.__getstate__().
This is wrong.
An example follows:
import pickle as P
class A(object): def __init__(self, a): print 'A.__init__' self.a = a
def __getstate__(self): print 'A.__getstate' return self.a
def __setstate__(self, upstate): print 'A.__setstate', upstate self.a = upstate
class B(A): def __init__(self, a, b): print 'B.__init__' A.__init__(self, a) self.b = b
def __getstate__(self): print 'B.__getstate' return (A.__getstate__(self), self.b)
def __setstate(self, upstate):
Try actually calling this method '__setstate__' instead.
# This never gets called! print 'B.__setstate', upstate A.__setstate__(self, upstate[0]) self.b = upstate[1]
def __repr__(self): return '<B a=%d b=%d>' % (self.a, self.b)
q = B(1,2) print '---' r = P.loads(P.dumps(q, 0)) print 'q=', q print 'r=', r
Now, run it:
$ python foo.py B.__init__ A.__init__ --- B.__getstate A.__getstate A.__setstate (1, 2) q= <B a=1 b=2, h=46912504218064> r= Traceback (most recent call last): File "foo.py", line 44, in <module> print 'r=', r File "foo.py", line 37, in __repr__ return '<B a=%d b=%d>' % (self.a, self.b) AttributeError: 'B' object has no attribute 'b' $ _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/thomas%40python.org
-- Thomas Wouters <thomas@python.org> Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
participants (2)
-
Greg Kochanski
-
Thomas Wouters