Re: Pickling and unpickling inherited attributes



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/

.



Relevant Pages

  • Re: itertools.izip brokeness
    ... Could modify izip so that one could write ... > for tup in zipit.rest: ... exhausted sequences, ... def next: ...
    (comp.lang.python)
  • Re: searching for strings (in a tuple) in a string
    ... Fredrik Lundh wrote: ... if 'x' in a or 'yy' in a or 'asd' in a: ... but then I can't make the if clause dependent on changing value of tup. ... is the "def" statement broken in your Python version? ...
    (comp.lang.python)
  • Re: searching for strings (in a tuple) in a string
    ... if 'x' in a or 'yy' in a or 'asd' in a: ... but then I can't make the if clause dependent on changing value of tup. ... is the "def" statement broken in your Python version? ...
    (comp.lang.python)
  • Re: Automatic reloading, metaclasses, and pickle
    ... inheritance. ... def PrintHi1: ... Pickle and cPickle get confused after reloading, ... dump the objects to file using protocol 2. ...
    (comp.lang.python)
  • Re: Persist a class (not an instance)
    ... classobj types, so I subclassed Pickler to override them. ... import sys, copy_reg, pickle, new, marshal, types, StringIO ... def func_constructor: ...
    (comp.lang.python)