Overriding methods inherited from a superclass with methods from a mixin

alanqueiros at gmail.com alanqueiros at gmail.com
Mon Jun 13 14:42:44 EDT 2016


Thank you for your replies. I don't know if I'm quoting you correctly, I'm quite confused with Google Groups... not sure if it's a "forum", something like a mailing list, or both... or neither.

> The class' MRO ("Method Resolution Order") determines in which
> order attributes are looked up.
> Either, you must order your base classes in such a way that the MRO
> controlled lookup finds the methods you want to be used or
> you must explicitely put a definition for those methods in your
> derived class (it may have the form "overridden_method = <BaseClass>.overridden_method").
> 
> The rules to determine the MRO are complex. The "inspect" module contains
> a function ("get_mro") to show the MRO of a given class. Use it
> to get your inheritance order right.

OK, I'm going to read about the MRO rules. Thanks for the heads up on the inspect module.

----

> 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.

Yeah, I see that in most cases the order doesn't matter, but still I would think that since the correct order is from right to left, that should be the common practice. What if later on you want to expand a mixin and actually override a method? That could cause a situation that's a hell to debug, so people should just get used to keeping their (most) "base" classes to the right when doing multiple inheritance in my opinion.
 
> 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)
> 

Yes, that violates the second item :). That would increase the complexity of the code because I would need to know which A to use when instantiating the classes, and what I'm doing is exactly to simplify the usage of those classes. Of course some docs and perhaps a well tailored enum (or alike) to be passed as the parameter could help, but a factory could do just as well, however, that isn't going to fulfill my needs at all, and since I'm the one who's going to use the code most of the time, I don't care much about using something somewhat "unconventional".

----

> The details are complex, but there are two fairly simple principles
> that can be relied upon:
> 
> 1) Subclasses always appear before their superclasses in the MRO.
> 2) When a class inherits from multiple base classes, they will always
> appear in the MRO in the order they appear in the class statement from
> left-to-right.
> 
> Note that neither of these rules guarantee that the classes will
> appear *sequentially* in the MRO.
> 
> So in the case of mixins, listing the mixin class first is absolutely correct:
> 
>     class Derived(Mixin, Base): pass
> 
> This ensures that Mixin will always appear before Base in the MRO (and
> thus override Base's methods) for Derived and for any subclass of
> Derived.
> 
> It is possible to concoct elaborate inheritance hierarchies in which
> it is not possible to come up with an MRO that will satisfy both 1)
> and 2) above. In such cases, it is also useful to know what Python
> will do. Fortunately, the answer to that is also simple: the type
> constructor will throw an exception. So this isn't something that
> really needs to be worried about.

That's some very nice information you got there. I also like how Ian Lewis explained that, it may not be very technical and perhaps that "logic" is accidental, but it surely helps you remember the correct order when doing multiple inheritance. (That part about forgetting the brackets and thinking of the code as a lined-up hierarchy, so MyClass => Mixin2 => Mixin1 => BaseClass).
In my opinion Python users should get used to that order. It doesn't matter if *atm* you're not overriding, if that's the correct way to do it, you should get used to it in my opinion because who know how you may need/want to expand your code in the future. Still, pretty much *no one* uses that order. A quick Google search returns (at least in my "bubble") many blog articles from "notable" Python users with that order wrong.

As long as I can rely on that it's OK for me. I couldn't find anything "official" on that subject though (mixins that override).

----

> Yet, you are clearly judging the code you pasted as not OK.

Actually, I didn't say (hard and fast) the code wasn't OK (if memory serves), I said I didn't like it -on a first superficial analysis-. Especially due the lack of recent experience with Python I was afraid I wasn't seeing some obvious caveat, thus I've basically asked you guys to tell me if the code is or isn't OK.

> It would be helpful for you to explain why you think the code you pasted is
> not OK. To me it makes sense. English reads left-to-right, so method
> lookups go left-to-right (and children before parents) in the inheritance
> list.

Basically I wasn't very confident the code was OK because my intuition said the right way to order the classes I was inheriting from was from left to right. I don't see any sense in that analogy you made... sure English and most occidental languages read ltr, but I fail to see how it makes more sense to have the base class on the right and the mixins on the left. Basically, I think of the mixins like plugins of kinds, I'm "adding" functionality to that "base" class I'm inheriting from. Having them to the left sounds like a sandwich recipe that tells you to "slice the ham, put mayonnaise on it, and put it on the bread". I guess that's a lot to do with everyone's individual intuition sense, but I guess your intuition, albeit more correct for this specific case, is very different from the massive majority of people. Don't take my word for it, Google multi inheritance or mixin in Python and let me know if you find someone who thinks it's "natural" to do it that way. Most people just get that wrong without even knowing, and the only one I could find who gets that right simply states that at first that isn't intuitive at all. So you're the first person I've seen who thinks that's the intuitive way to do it.
I'm not complaining or something, I totally don't mind that "rule", and as I said the way Ian put that will surely make it stick to my brain like a scar, but it sure as hell doesn't seem intuitive for me.

Thank you guys for the help. I really appreciated it. I'll go with that code because it makes sense for this specific case now I'm convinced it's OK.



More information about the Python-list mailing list