[Python-ideas] MRO local precedence ordering revisited
Andrew Barnert
abarnert at yahoo.com
Fri Dec 11 00:53:11 EST 2015
On Dec 10, 2015, at 15:19, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
>
> Stephan Sahm wrote:
>> my own intuitiv MRO would not be anything proposed so far, but:
>> (B, mixin, A, mixin, object)
>> As you haven't mentioned this as a possibility at all, I guess having a class twice in this list produces some weird behaviour I do not know about yet - if someone can point out, that would be great.
>
> I'm not sure what that would do to super calls. It's possible
> you would end up in a loop from Mixin -> A -> Mixin -> A -> ...
>
> But in any case, this MRO doesn't solve the fundamental
> problem that the MROs of B and A are inherently contradictory.
> *You* know what MRO you want in this particular case, but
> there's no way for Python to know that.
After thinking about this a bit: the MRO isn't really contradictory; what's contradictory is what he's expecting super() to do with his MRO. When called from within mixin.spam(), he wants it to give him A, but when calling from within mixin.spam(), he wants it to give him object. Since those two "whens" are identical, there's his problem. But if you never call super(), there's nothing wrong with it; any attribute provided by Mixin the first time means you'll never get to Mixin the second time. (I suppose you could hack that with quantum attributes that have an x% chance of being there each time you call __getattr__, but just don't do that...)
Of course he wants to call super. Or, rather, he wants to call something that's kind of like super, but that handles his MRO in a non-contradictory way. A similar MI next-method protocol that went by index rather than by name would work: within mro[1].spam() it gives you mro[2]; within mro[3].spam() it gives you mro[4]. Python doesn't come with a function that does that, but you can write one, with a bit of kludgery. And you can easily write a metaclass that sets up the MRO you want. Which means you can build exactly what the OP is asking for.
It still won't do what he wants. For one thing, like super, it depends on the entire class hierarchy cooperating, which includes the root not supering but everyone else doing so--but mixin is the root, and also elsewhere on the tree, so it has to both super and not super. And there are a couple other problems. But tightening up the requirements a bit,
I think you can make something coherent out of this.
It's definitely not the best way to solve his problem, and it's probably not a good way to solve _any_ problem--but it does work. See http://stupidpythonideas.blogspot.com/2015/12/can-you-customize-method-resolution.html for a fully worked through example.
More information about the Python-ideas
mailing list