Overriding methods inherited from a superclass with methods from a mixin

Peter Otten __peter__ at web.de
Mon Jun 13 03:59:26 EDT 2016


alanqueiros at gmail.com wrote:

> Hello there.
> 
> I'm trying to override methods inherited from a superclass by methods
> defined in a mixin class. Here's an sscce:
> https://bpaste.net/show/6c7d8d590658 (never expires)

> #the following represents classes I don't have control over
> class Base(object):
>     def methodX(self):
>         print "methodX class Base"
> 
> class A(Base): #inherits methodX
>     pass
> 
> class A2(Base): #inherits methodX
>     pass
> 
> class A3(Base): #inherits methodX
>     pass
> 
> #the following represents classes I have control over
> class B(object):
>     def methodX(self):
>         print "methodX class B"
> 
> class Z(B,A):
>     def methodXfromA(self):
>         A.methodX(self)
> 
> class Z2(B,A2):
>     pass
> 
> class Z3(B,A3):
>     pass
> 
> #what I need is to be able to quickly create these Z classes and override 
the
> #methodX by the functionality in class B, while still being able to call
> #class A.methodX
> 
> Z().methodX();
> Z2().methodX();
> Z3().methodX();
 


> I've had problems finding the proper way to do that, since at first the
> base class wasn't to the right and I've assumed the correct order was from
> left to right. It was previously suggested on IRC that the mixin should be
> a subclass of "Base"; that worked but I wasn't happy with it because the B
> class basically serves the purpose of "holding" a list of methods to be
> inherited and that should override the methods inherited from the "A"
> classes, so I didn't see why it should derive from "Base".
> 
> I eventually found in an article that the problem was the ordering of the
> superclasses I was deriving from, which should be from right to left, the
> only article I could find that states that is this one:
> https://www.ianlewis.org/en/mixins-and-python
> 
> Every single example of mixins in Python that I've read -except that one-
> (and I've seen literally dozens) has the base class to the left, although
> the other classes aren't overriding any methods (at least in most of
> them).
> 
> That bpaste code is working perfectly for me and makes sense, but I don't
> really like it, and the people on IRC couldn't convince me the code is
> fine.

But the code is fine. Write unit tests to ensure that the correct method is 
called.

Usually you use mixins to add methods. In that case the order of base 
classes doesn't matter.
 
> I haven't used Python for some time so I don't feel confident to judge
> that code, and perhaps there's a better way to achieve that result.
> However, what really scared me is the obscurity of the mixins usage in
> Python, and the fact that every example except that single one gets it
> "wrong", including from notable pythonistas.
> 
> Perhaps you guys could help me either convincing me that the bpaste code
> is OK, or perhaps coming up with a better solution for that problem. What
> matters to me is code re-usability in this case. I surely could
> re-implement the overrides in all "Z" classes separately, but that's what
> I'm trying to avoid. The requirements are: 1. I can't touch the "classes I
> don't have control over" (as per comment in code). 2. I don't want to pass
> the superclasses as parameters in the constructor. I see how you could
> solve the problem that way, but that would only increase the complexity of
> the code (PEP20). 3. I absolutely need to override methodX, I can't use
> composition and access the members another way unless I override methodX
> and access them there. This is to interface properly with other modules.
> 4. I need to be able to access A#.methodX in the "Z" classes methods. 5. I
> want to avoid using a factory. It's one of the most over-used patterns in
> my opinion, and I really don't like that.

That looks like you are actively excluding most alternatives ;)

Here's one option that should also work (though I'm not sure if that is what 
you mean with point 2 of your list):

def subclass(base):
    class Z(base):
        def methodX(self):
            print "overridden methodX"
    return Z

Z = subclass(A)
Z2 = subclass(A2)

> Please note that the bpaste code is just an example. The real problem is
> much bigger and involves multiple methods to override and more classes, so
> the solution has to scale accordingly.





More information about the Python-list mailing list