Post by Ben FinneyPost by Alan GauldWhilst I agree with the general use of super I'm not sure what
the MRO resolution has to do with this case?
When accessing the superclass, the MRO is always relevant
Can you explain that?
If I access a class explicitly and call a method directly
how is the MRO involved in that invocation? (It is involved
if the method is actually implemented in a super-superclass
of course, I understand that bit.) But how does MRO affect
a direct call to a method of a class?
Post by Ben FinneyPost by Alan GauldIt's explicitly single inheritance and they are explicitly calling the
superclass.
They don't know that the superclass will be what is written there;
that's an implication of what I said with “in Python, any class an
participate in multiple inheritance”.
If MyList is included in a MI lattice that doesn't change the fact that
MyList inherits directly from list. Or at least I hope not, that could
be catastrophic to the behaviour of the class. The class definition
demands that MyList has a single direct superclass (and potentially many
super-super-classes). that is the very basis of the Is-A relationship
that inheritance indicates.
Post by Ben FinneyThe author of a class (e.g. the OP's example ‘MyList’) cannot know at
time of writing whether the superclass is ‘list’. This is because some
other class may be using ‘MyList’ in a different inheritance
arrangement.
That should not change the superclass of MyList. It just means that
the new subclass doesn't know where list appears in the execution
order of its superclass calls. But it should not change the behaviour of
MyList methods.
Post by Ben FinneyEven without either party (the author of ‘MyList’, or the author of the
other class) intending it to be so, the MRO can run through ‘MyList’ in
a direction not specified by either author.
I'm not sure what you mean by 'direction' there?
But I agree neither author can tell where in the sequence of
method calls the MyLIst version will be called when the method
is invoked on the subclass. If that's what you mean?
Post by Ben FinneyMultiple inheitance is a fact in Python, and good practice is to not
arbitrarily write classes that break it.
That depends on what you mean by break it., MI should allow the
inheriting class to specify which, if any, of its direct superclasses
methods are invoked. That's critical to the use of MI in any language
The issues around that are addressed differently by different languages,
for example Eiffel allows you to rename inherited methods
or attributes to avoid them being used involuntarily. Most just allow
the programmer to explicitly access the superclasses where default
behaviour is not required. That's what I thought Python was doing with
super. Making default easy to get but still allowing direct overriding
when required.
Post by Ben FinneyMuch as the class author might like it to be so simple, in Python it
just isn't so: any other class using multiple inheitance may pull in
this one, either as a parent or in some other indirect relationship.
Thus the above assertion is violated.
Not so. A single inheritance class, even in an MI scenario must still be
able to rely on its own superclass being the one stated. To do otherwise
would result in very weird and unpredictable behaviour.
Post by Ben FinneyIn Python code it can't be said “there should be not MRO lookup at this
class level”. It's not for the class author to say whether some other
class “should not” inherit, directly or indirectly, from this and some
other class(es).
Yes, but then the MRO is invoked at that subclass level. Its not in the
power of the class author to know how the class will be used in future
class definitions. But the class *must* always follow the semantics of
the original class or the contract of the definition is broken.
Post by Ben FinneyPost by Alan GauldC.m(self) # call C's m but not B and D if they have them.
Or am I missing something in the way Python evaluates
the C.m() call above?
I still want to know how you would code the above scenario
using super? If B,C and D all have an m() method but I only
want to call the version in C how do I control that in
Python other than by a direct call to C.m()?
Post by Ben Finney[…] dynamic ordering is necessary because all cases of multiple
inheritance exhibit one or more diamond relationships (where at
least one of the parent classes can be accessed through multiple
paths from the bottommost class). For example, all new-style classes
inherit from `object`, so any case of multiple inheritance provides
more than one path to reach `object`. […]
Yes I understand that. If you want to call all of the superclass
versions of a method you are overriding then super is the only way to
go. I'm talking about the case where you have a single superclass method
that you want to invoke.
As I understand it, MyList can still explicitly call list and, if in an
MI scenario, the list method can call super and it will ripple through
the MRO. Similarly the MyList method invocation will appear in the
normal MRO processing of the subclass. The risk is that list gets called
multiple times but that's sometimes desirable and sometimes
not. (Mainly an issue where state changes are involved)
Post by Ben FinneyThe paths are determined at run time, and can link through the class one
is writing whether on intends that or not.
The issue is not whether the sub class method invocation goes through
MyList or not but whether MyList can control which of its superclasses
gets called and, more importantly, which do not. Of course another peer
superclass may invoke the methods that MyList doesn't want to use but
thats of no concern to MyList.
Post by Ben FinneyAny class one writes can
become part of some other class's multiple-inheritance chain, and it is
bad practice to assume one knows at time of writing what the superclass
will be at run time.
This is the bit I don't understand. The superclass of a given class
should never change. The sequence of default processing may change but
any other behavior would be a serious breach of the class definition.
Post by Ben FinneyWe have discused this multiple times in the past. Here is a thread from
2011, ...
All the smarts managing the entire inheritance hierarchy is built
into `super`, so each method gets called once and exactly once,
And that is what super does. It does not determine what the superclass
is. It arranges the superclass such that a default invocation will
excercise all of the superclasses exactly once. But as Steven pointed
out there are exceptions (He used the example of differing signatures
but there are several others) One of the most common is where multiple
superclasses define the same method but with very different semantics.
The normal way to disambiguate that is to create multiple methods in the
subclass which only invoke the appropriate superclass.
A rather contrived example is where I want to inherit a Pen and a
Curtain to produce a GraphicalCurtain class. Both Pen and Curtain define
a draw() method but they do very different things. So I define two
methods: draw() which invokes Pen.draw() and close() which invokes
Curtain.draw(). If I use super in either of those methods I'll get the
wrong behavior because both Pen.draw and Curtain.draw will be invoked,
Unless I'm missing something clever in super? I never quite
understood the parameters in super() so it is possible that
there is a way to exclude some super classes, but I'm not
aware of any such.
Post by Ben FinneyMultiple inheritance is a counter-intuitive topic, so it's not really
surprising there is still confusion about it.
It depends on your background. I learned OOP using Flavors in the mid
80s and it was all about MI. It was standard practice to define classes
with 5, 6 or more superclasses. But it had much more sophisticated tools
than python to control the MRO definition on a class by class basis, C++
also allows MI and takes a different approach again but that only works
because the compiler can sort it out for you. And Eiffel uses renaming
of attributes. There are lots of options to addressing the same problem.
Post by Ben Finneybefore it takes hold, by widely advocating use of ‘super’ to aid
everyone else's Python code.
And lest there is any confusion, I agree that super should be the
default option. I'm only pointing out that a) super does not change
the superclass, it simply moves it to a different place in the
chain of execution and b) several cases exist where the default MRO
sequence is not what you need. In those cases you have to work
it out for yourself (or find a way to avoid them if possible!)
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options: