What is __reduce__? (was: copy.deepcopy(): is it bug or intended behavior?)
Benjamin Han
bhan at andrew.cmu.edu
Thu Aug 1 01:04:46 EDT 2002
So I traced a little bit to uncover the mystery. in copy.py the deepcopy() is
defined as:
def deepcopy(x, memo = None):
"""Deep copy operation on arbitrary Python objects.
See the module's __doc__ string for more info.
"""
if memo is None:
memo = {}
d = id(x)
if memo.has_key(d):
return memo[d]
try:
copierfunction = _deepcopy_dispatch[type(x)]
except KeyError:
try:
copier = x.__deepcopy__
except AttributeError:
try:
reductor = x.__reduce__
except AttributeError:
raise error, \
"un-deep-copyable object of type %s" % type(x)
else:
y = _reconstruct(x, reductor(), 1, memo)
else:
y = copier(memo)
else:
y = copierfunction(x, memo)
memo[d] = y
return y
At the point when Bar instance is deepcopied, type(x) returns <class
'__main__.Bar'> therefore statement
copierfunction = _deepcopy_dispatch[type(x)]
generated KeyErro. The chain reaction of exceptions stopped when
reductor = x.__reduce__
But I can't find __reduce__ in Library and Langauge references. Hint anyone?
Thanks!
PS. this explained why defining my own __deepcopy__ worked. Is it a standard
practice that whenever you derive a class you have to write __deepcopy__ to
take care of the super-class copying?
Ben
On Wednesday 31 July 2002 11:59 pm, you wrote:
> Curiously if I added __deepcopy__ to class Bar (replace Bar with the
> following class def):
>
> class Bar (list):
> def __deepcopy__ (self,memo):
> obj=Bar()
> memo[id(self)]=obj
> for e in self: obj.append(copy.deepcopy(e,memo))
>
> for k,v in self.__dict__.iteritems():
> obj.__dict__[k]=copy.deepcopy(v,memo)
>
> return obj
>
>
> then the result is correct:
>
> [[1]] 135743596
> [[2]] 135787484
> ----------------------------------------------------------------------
> [[1]] 135760188
> [[2]] 135626380
>
>
> Ben
>
> On Wednesday 31 July 2002 07:59 pm, you wrote:
> > This is an abstract of the actual code:
> >
> > --- cut here ---
> > import copy
> >
> > class Foo:
> > def clone (self):
> > return copy.deepcopy(self)
> >
> > class Bar (list):
> > pass
> >
> > class Const:
> > def __init__ (self, data):
> > self.data=data
> > def __repr__ (self):
> > return str(self.data)
> >
> > n1=Foo()
> > n1.t=[]
> > c=Bar()
> > c.append(Const('1'))
> > n1.t.append(c)
> >
> > n2=Foo()
> > n2.t=[]
> > c=Bar()
> > c.append(Const('2'))
> > n2.t.append(c)
> >
> > g=Foo()
> > g.hd=[]
> > g.hd.append(n1)
> > g.hd.append(n2)
> >
> > print g.hd[0].t,id(g.hd[0].t)
> > print g.hd[1].t,id(g.hd[1].t)
> >
> > print
> > '----------------------------------------------------------------------'
> >
> > h=g.clone()
> >
> > print h.hd[0].t,id(h.hd[0].t)
> > print h.hd[1].t,id(h.hd[1].t)
> >
> > --- cut here ---
> >
> >
> > Running on Python 2.2.1 gave the following output:
> >
> > [[1]] 135743596
> > [[2]] 135759124
> > ----------------------------------------------------------------------
> > [[1]] 135505252
> > [[1]] 135793916
> >
> >
> > But the last line should have "[[2]]...". Am I missing something here?
> >
> > Thanks,
> >
> > Ben
More information about the Python-list
mailing list