[Python-ideas] MRO local precedence ordering revisited
Chris Angelico
rosuav at gmail.com
Thu Dec 10 12:29:05 EST 2015
On Fri, Dec 11, 2015 at 3:36 AM, Stephan Sahm <Stephan.Sahm at gmx.de> wrote:
> As reference I take https://www.python.org/download/releases/2.3/mro/
> There the section "Bad Method Resolution Orders" starts with an example
> which behaviour in the current python 2.7 is rather unintuitive to me.
Just to make something quite clear: "current" Python, as discussed on
this list, is 3.5 or 3.6, not 2.7. There won't be a 2.8, and future
releases of 2.7.x won't be changing anything like this. What you're
describing is also the case in current Python 3.x, but any change to
how the MRO is derived would happen in 3.6 at the very soonest. (At
least, I don't _think_ the current behaviour could be considered a
bug. I could be wrong.)
> I rename the example slightly to illustrate its usecase.
>
>> class Mixin(object):
>> pass
>>
>> class A(Mixin):
>> pass
>> class B(Mixin, A):
>> pass
>
>
> this unfortunately throws "TypeError: Error when calling the metaclass bases
> Cannot create a consistent method resolution order (MRO) for bases A, Mixin"
>
>
> The reference name above comments this case similar to the following
> (adapted to the easier example above):
>
> [quoting the docs]
>> As a general rule, hierarchies such as the previous one should be avoided,
>> since it is unclear if Mixin should override A or viceversa
>
>
> While it might be the case that in Python 2.2 things where different, I
> cannot agree that the expected order of Method resolution is ambiguous (at
> least as far I see at this stage).
>
> Therefore I would like to propose to make this MRO again a valid one.
>
> The usecase should be obvious: If you want a Mixin to be the first thing
> overwriting functions, but still want to inherit as normal.
> (I myself want for instance a Mixin to overwrite the __init__ method, which
> is simply not impossible when choosing class B(A, Mixin))
What you're proposing, in effect, is that it should be possible for
super() to go *down* the class hierarchy. Under your proposal,
B.__mro__ would be (Mixin,A,object), which means that super().method()
inside A will go directly to object, and that the same call inside
Mixin will go to A - reversing the order of the calls compared to the
way they would be if the object were of type A. Now it is known that
the super doesn't mean "call my base class", but something more like
"call the next class"; but it's currently guaranteed that the MRO for
any derived class is a *merge* of the MROs of its parents, without
ever reordering them. Under your rules, what would be the MRO here?
class A(object): # explicitly stating the default
def __new__(cls):
print("Constructing an A")
return super().__new__(cls)
def method(self):
print("Calling method on A")
super().method()
class B(object, A):
pass
If you answered (B,object,A), then you've just made it possible to
have some other class than object at the end of the chain. Where do
super() calls go if there *is no next class*? What should happen? Can
that be made equally intuitive to your proposal about mixins?
ChrisA
More information about the Python-ideas
mailing list