Copying objects and multiple inheritance

Brian Allen Vanderburg II BrianVanderburg2 at aim.com
Wed Jun 3 15:20:35 CEST 2009


Gabriel Genellina wrote:
> En Tue, 02 Jun 2009 19:02:47 -0300, Brian Allen Vanderburg II 
> <BrianVanderburg2 at aim.com> escribió:
>
>> What is the best way to copy an object that has multiple inheritance 
>> with the copy module.  Particularly, some of the instances in the 
>> hierarchy
>
> ("...some of the classes in...", I presume?)
>
>> use the __copy__ method to create a copy (because even for shallow 
>> copies they need some information  updated a little differently), so 
>> how can I make sure all the information is copied as it is supposed 
>> to be even for the base classes that have special requirements.
>
> If you don't control all the clases involved, there is little hope for 
> a method like __copy__ to work at all... All classes must be written 
> with cooperation in mind, using super() the "right" way. See "Python's 
> Super Considered Harmful" [1] and "Things to Know About Python Super" 
> [2][3][4]
>
> That said, and since multiple inheritance is the heart of the problem, 
> maybe you can redesign your solution *without* using MI? Perhaps using 
> delegation instead?
>
> [1] http://fuhm.net/super-harmful/
> [2] http://www.artima.com/weblogs/viewpost.jsp?thread=236275
> [3] http://www.artima.com/weblogs/viewpost.jsp?thread=236278
> [4] http://www.artima.com/weblogs/viewpost.jsp?thread=237121
>
I do control the classes involved.  A problem I was having, but I think 
I now got solved, is if using super, the copy would not have the same 
class type.  Also, a problem was if using super, but some class in the 
hierarchy didn't implement __copy__, then it's data would not be copied 
at all.  This was also fixed by copying the entire __dict__ in the base 
__copy__.  This is an idea of what I got, it seems to be working fine:

import copy

class _empty(object):
    pass

class Base(object):
    def __init__(self):
        pass

    def __copy__(self):
        // don't use copy = Base()
        // Also don't call self.__class__() because it may have a custom
        // __init__ which take additional parameters
        copy = _empty()
        copy.__class__ = self.__class__
        // In case a class does not have __copy__ (such as B below), make
        // sure all items are copied
        copy.__dict__.update(self.__dict__)

        return copy

class A(Base):
    def __init__(self):
        super(A, self).__init__()
        self.x = 13

    def __copy__(self):
        copy = super(A, self).__copy__()
        copy.x = self.x * 2
        return copy

class B(Base):
    def __init__(self):
        super(B, self).__init__()
        self.y = 14

    #def __copy__(self):
    #    copy = super(B, self).__copy__()
    #    copy.y = self.y / 2
    #    return copy

class C(A, B):
    def __init__(self):
        super(C, self).__init__()
        self.z = 64

    def __copy__(self):
        copy = super(C, self).__copy__()
        copy.z = self.z * self.z
        return copy

o1 = C()
o2 = copy.copy(o1)

print type(o1), o1.x, o1.y, o1.z
print type(o2), o2.x, o2.y, o2.z





More information about the Python-list mailing list