Challenge supporting custom deepcopy with inheritance

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Tue Jun 2 00:51:35 EDT 2009


En Mon, 01 Jun 2009 14:19:19 -0300, Michael H. Goldwasser  
<goldwamh at slu.edu> escribió:

>   I can examine the inherited slots to see which special methods are
>   there, and to implement my own __deepcopy__ accordingly. But to do
>   so well seems to essentially require reimplementing the complicated
>   logic of the copy.deepcopy function.  That is, if my new class is
>   the first to be implementing an explicit __deepcopy__ function, I
>   seem to have no easy way to invoke the inherited version of
>   "deepcopy(self)".

Yes, that's a problem. But there is a workaround: since __deepcopy__ is  
searched *in the instance* (unlike many other __special__ methods, that  
are usually searched in the class itself) you can fool the copy logic into  
thinking there is no __deepcopy__ method defined, just by (temporarily)  
setting an instance attribute __deepcopy__ to None. (It's a hack, anyway)

<code>
import copy

class A(object):
   def __init__(self, x, y):
     self.x = x
     self.y = y

   # these two methods implement copy and pickle behaviour
   # we can't change them
   def __reduce__(self):
     return (self.__newobj__, (), self.__dict__)

   @classmethod
   def __newobj__(cls, *args):
     return cls.__new__(cls, *args)


class B(A):
   def __init__(self, x, y, filename):
     A.__init__(self, x, y)
     self.file = open(filename, "at")

   def __deepcopy__(self, memo):
     # Problem: how to call the inherited __deepcopy__ implementation
     # when there is none?
     # The logic is inside the copy.deepcopy function, not in
     # object.__deepcopy__

     # hack: make deepcopy() think this method doesn't exist
     self.__deepcopy__ = None
     try:
       dup = copy.deepcopy(self, memo)
       del dup.__deepcopy__
     finally:
       del self.__deepcopy__

     # now, do the special stuff
     dup.file = open(self.file.name, "at")
     return dup


obj = B(1, 2, "testfile")
print "obj", obj, vars(obj)
dup = copy.deepcopy(obj)
print "obj", obj, vars(obj)
print "dup", dup, vars(dup)
</code>

obj <__main__.B object at 0x00BEC0F0> {'y': 2, 'x': 1, 'file': <
open file 'testfile', mode 'at' at 0x00B46C00>}
obj <__main__.B object at 0x00BEC0F0> {'y': 2, 'x': 1, 'file': <
open file 'testfile', mode 'at' at 0x00B46C00>}
dup <__main__.B object at 0x00BEC7F0> {'y': 2, 'x': 1, 'file': <
open file 'testfile', mode 'at' at 0x00B46CA0>}

>   I wonder if the logic inherent in the copy.deepcopy function could
>   instead be implemented directly within object.__deepcopy__ (rather
>   than the current model in which object does not have __deepcopy__).
>   Then I would always have a means for simulating a call to
>   deepcopy(self) based upon the super.__deepcopy__ logic.
>   I wouldn't be surprised if I'm overlooking some undesirable
>   consequence of such a major change in the model, but I don't see one
>   upon first thought.

This deserves to be looked at with more detail. Try the python-ideas list,  
or submit a RFE to http://bugs.python.org/

-- 
Gabriel Genellina




More information about the Python-list mailing list