Discussion:
[Tutor] __repr__ and __str__
Marilyn Davis
2015-06-30 06:47:45 UTC
Permalink
Hello Python Tutors,

A student has asked a question that has me stumped. We are using 2.7.

Looking at this code:

#!/usr/bin/python

class MyList(list):

def __str__(self):
return """Here are your data:
%s
""" % list.__str__(self)

def main():
a = MyList([1,2])
print a

if __name__ == "__main__":
main()

___

We get the expected output:

Here are your data:
[1, 2]

But if we add the special method:

def __repr__(self):
return "MyList(%s)" % (list.__str__(self))

we get:

Traceback (most recent call last):
File "./stack2.py", line 17, in <module>
main()
File "./stack2.py", line 14, in main
print a
File "./stack2.py", line 10, in __str__
""" % list.__str__(self)
File "./stack2.py", line 5, in __repr__
return "MyList(%s)" % (list.__str__(self))
File "./stack2.py", line 5, in __repr__
return "MyList(%s)" % (list.__str__(self))

and on and on to the:

RuntimeError: maximum recursion depth exceeded

--

From https://docs.python.org/2/reference/datamodel.html:

If a class defines __repr__() but not __str__(), then __repr__() is also
used when an “informal” string representation of instances of that class
is required.

__

So ????? __str__ is defined and works just fine unless we also define
__repr__.

What am I missing?

Thank you for any help.

Marilyn Davis

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription
Alan Gauld
2015-06-30 12:33:33 UTC
Permalink
Post by Marilyn Davis
%s
""" % list.__str__(self)
a = MyList([1,2])
print a
return "MyList(%s)" % (list.__str__(self))
File "./stack2.py", line 10, in __str__
""" % list.__str__(self)
File "./stack2.py", line 5, in __repr__
return "MyList(%s)" % (list.__str__(self))
File "./stack2.py", line 5, in __repr__
return "MyList(%s)" % (list.__str__(self))
RuntimeError: maximum recursion depth exceeded
If a class defines __repr__() but not __str__(), then __repr__() is also
used when an “informal” string representation of instances of that class
is required.
My guess is that list.__str__ is calling self.__repr__
But you have defined your own self.__repr__ so it gets called and
it then calls list.__str__ again, and again and ....

Try replacing the call to list.__str__ with a call to list.__repr__
and see if that fixes things?
--
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:
https://mail.python.org/mailm
Steven D'Aprano
2015-06-30 13:10:52 UTC
Permalink
Post by Marilyn Davis
Hello Python Tutors,
A student has asked a question that has me stumped. We are using 2.7.
Ooh, nice one! That had me stumped for a while too, but I think I have
the solution. I wrote this class to investigate:

class MyList(list):
def __str__(self):
print "called __str__"
return list.__str__(self)
def __repr__(self):
print "called __repr__"
return list.__repr__(self)



Then I ran this in the interactive interpreter:

py> L = MyList([1, 2, 3])
py> repr(L)
called __repr__
'[1, 2, 3]'
py> str(L)
called __str__
called __repr__
'[1, 2, 3]'


So what appears to be happening is that list.__str__ calls __repr__. My
guess is that it is written something like this:

# built-in list
class list:
def __str__(self):
return self.__repr__()
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Marilyn Davis
2015-06-30 17:08:24 UTC
Permalink
Thank you so much Alan and Steve.

We are good now.

Marilyn
Post by Steven D'Aprano
Post by Marilyn Davis
Hello Python Tutors,
A student has asked a question that has me stumped. We are using 2.7.
Ooh, nice one! That had me stumped for a while too, but I think I have
class MyList(list): def __str__(self): print "called __str__" return
list.__str__(self) def __repr__(self): print "called __repr__" return
list.__repr__(self)
py> L = MyList([1, 2, 3]) py> repr(L) called __repr__ '[1, 2, 3]'
py> str(L) called __str__ called __repr__ '[1, 2, 3]'
So what appears to be happening is that list.__str__ calls __repr__. My
# built-in list
class list: def __str__(self): return self.__repr__()
--
Steve
_______________________________________________
https://mail.python.org/mailman/listinfo/tutor
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Ben Finney
2015-06-30 20:38:19 UTC
Permalink
Post by Marilyn Davis
Hello Python Tutors,
A student has asked a question that has me stumped. We are using 2.7.
#!/usr/bin/python
%s
""" % list.__str__(self)
That's okay, but yo should instead use the ‘super’ method to get the
superclass, instead of assuming it's known.

Python allows any class to participate in multiple inheritance, and
that's not determined at the point of writing your class. So you
can never assume you know what class is next in the resolution order;
that's what ‘super’ is for::

class MyList(list):

def __str__(self):
text = """Here are your data:
%s
""" % super().__str__()
return text

(I am assuming this is Python 3 code, since Python 2 is legacy-only and
should not be used for teaching today. If you need Python 2, it needs a
different ‘super’ invocation; see its documentation.)
Post by Marilyn Davis
return "MyList(%s)" % (list.__str__(self))
That's another problem (as pointed out by others in this thread). In
addition to using ‘super’ to determine the superclass, you should also
be calling the equivalent method on the superclass.

In other words, since you're defining ‘__repr__’, it is ‘__repr__’ you
should be calling on the superclass::

def __repr__(self):
text = "MyList(%s)" % super().__repr__()
return text
Post by Marilyn Davis
So ????? __str__ is defined and works just fine unless we also define
__repr__.
What am I missing?
The complications of inheritance and calls to the superclass. When
defining special methods (the “dunder” methods, so named because they
are named with a double leading and trailing underscore), it is best
only to extend the same method on the superclass, and not complicate the
connextions back and forth.
Post by Marilyn Davis
Thank you for any help.
Hope that helps. Thank you for teaching Python 3 to more students!
--
\ “DRM doesn't inconvenience [lawbreakers] — indeed, over time it |
`\ trains law-abiding users to become [lawbreakers] out of sheer |
_o__) frustration.” —Charles Stross, 2010-05-09 |
Ben Finney

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.
Alan Gauld
2015-06-30 23:49:19 UTC
Permalink
Post by Ben Finney
Post by Marilyn Davis
%s
""" % list.__str__(self)
Python allows any class to participate in multiple inheritance, and
that's not determined at the point of writing your class. So you
can never assume you know what class is next in the resolution order;
Whilst I agree with the general use of super I'm not sure what
the MRO resolution has to do with this case? It's explicitly
single inheritance and they are explicitly calling the superclass.
There should be no MRO lookup at this class level (there
may be at the list level of course).

super makes sense (sometimes) in a multiple inheritance setup.
It makes less sense in a single inheritance situation and no
sense at all in any setup where you want to call a specific
superclass rather than rely on a generic walk up the
inheritance tree.

eg.

class A(B,C,D):
def m(self):
C.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?
Post by Ben Finney
""" % super().__str__()
(I am assuming this is Python 3 code,
Nope. The OP explicitly said 2.7.
Post by Ben Finney
since Python 2 is legacy-only and should not be used for teaching today.
That's a fine aspiration but pretty much impractical in the real world.
There are many reasons why folks need to use 2.7 (or even older!)
[ Just look at the stuff Bob Stepp is doing where he is stuck on 2.4. ]
At my last job they wouldn't install Python 3 (although that was
2 years ago, it may have moved on now!) and we didn't move off 1.5
to v2 until ~5 years after v2 was released.
Post by Ben Finney
In other words, since you're defining ‘__repr__’, it is ‘__repr__’ you
That depends on what representation they want in the repr output, it may
be more similar to the superclass str() than its repr(). There should be
no *necessity* to call the "same" method in the superclasss, even though
most of the time that is what you do.
Post by Ben Finney
are named with a double leading and trailing underscore), it is best
only to extend the same method on the superclass, and not complicate the
connextions back and forth.
I do agree as a principle but sometimes the principle doesn't yield
the right result. But when you bend the 'rules' you do have to
expect to get bitten occasionally.
--
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:
https://mail.python.org/m
Ben Finney
2015-07-01 02:48:47 UTC
Permalink
Post by Alan Gauld
Whilst 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.
Post by Alan Gauld
It'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”.

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

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

Multiple inheitance is a fact in Python, and good practice is to not
arbitrarily write classes that break it. Hence my advice to avoid
hard-coding the superclass, and only use ‘super’ to discover the
superclass.
Post by Alan Gauld
There should be no MRO lookup at this class level (there may be at the
list level of course).
Much 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.

In 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).
Post by Alan Gauld
super makes sense (sometimes) in a multiple inheritance setup.
Yes, and the class author can't know at time of writing whether that's
the case. So it's prudent to never hard-code the superclass, and to only
use ‘super’ to dynamically determine at run time what is the superclass.
Post by Alan Gauld
eg.
C.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?
My understanding comes from (among other places) the Python docs::

[…] 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`. […]

<URL:https://docs.python.org/2/tutorial/classes.html>

The paths are determined at run time, and can link through the class one
is writing whether on intends that or not. Any 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.


We have discused this multiple times in the past. Here is a thread from
2011, explaining why, even one isn't using multiple base classes
explicitly, one should always only ever use ‘super’ to determine at
run-time what the superclass is:

All the smarts managing the entire inheritance hierarchy is built
into `super`, so each method gets called once and exactly once,
provided that every class *only* uses `super`. If you try to mix
`super` calls and direct method calls like B.method(self, arg), it
probably won't work correctly, and if it does, it will probably be
by accident.

So please use `super`, even in single inheritance. Otherwise you are
restricting the usefulness of your class: it can never be used with
multiple inheritance.

<URL:https://mail.python.org/pipermail/tutor/2011-October/086110.html>

Multiple inheritance is a counter-intuitive topic, so it's not really
surprising there is still confusion about it. I try to nip the problem
before it takes hold, by widely advocating use of ‘super’ to aid
everyone else's Python code.

Hope that helps!
--
\ “I took it easy today. I just pretty much layed around in my |
`\ underwear all day. … Got kicked out of quite a few places, |
_o__) though.” —Bug-Eyed Earl, _Red Meat_ |
Ben Finney

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listin
Alan Gauld
2015-07-01 21:40:20 UTC
Permalink
Post by Ben Finney
Post by Alan Gauld
Whilst 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 Finney
Post by Alan Gauld
It'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 Finney
The 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 Finney
Even 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 Finney
Multiple 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 Finney
Much 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 Finney
In 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 Finney
Post by Alan Gauld
C.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 Finney
The 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 Finney
Any 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 Finney
We 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 Finney
Multiple 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 Finney
before 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:
Steven D'Aprano
2015-07-02 16:29:31 UTC
Permalink
Post by Alan Gauld
Post by Ben Finney
Multiple 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.
That sounds like Eiffel multiple-inheritance is closer to traits than
full M-I:

http://www.artima.com/weblogs/viewpost.jsp?thread=246488
Post by Alan Gauld
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.
In Python, super() is designed to ensure that when you call the
parent(s)'s method, *all* the parents that define that method get run,
not just the immediate parent. (Assuming that they all cooperate by
using super.)

To quote Michele Simionato from the above link:

[quote]
The point to notice is that the complication of the MRO is by design:
languages with a non-trivial MRO where [sic] designed this way to make
possible method cooperation via super calls. That means that if both
parents P1 and P2 define a method m, a child class C can override it and
still have access to the m methods of the parents via super: C.m will
call first P1.m and then P2.m, if P1.m features a super call itself.
[end quote]

If your inheritance needs don't match that behaviour, then Python's M-I
model is not a good fit for you, and you might be better off with
Michele's strait module, some other library, or just managing the
inheritance calls yourself. But if you do that, you're implicitly ruling
your class out from participating in "regular" M-I hierarchies.
Post by Alan Gauld
Post by Ben Finney
Post by Alan Gauld
C.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()?
That can't be done using super(). Super isn't designed for that
use-case, it's designed for the case where you want to call B.m, C.m and
D.m in that order.

Hence my comments in the previous post about not *unnecessarily* ruling
out the use of multiple inheritance. If it's necessary, you can do it.
Post by Alan Gauld
Post by Ben Finney
Any 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.
Even in the single inheritance world, there is no such concept as "the
superclass". There is *one or more* superclasses (note plural). (Zero
only in the case of the root of the object hierarchy.)

In the most general case, your child class doesn't know whether it is
inheriting the method from the parent, grandparent, great-grandparent,
... great-to-the-Nth-grandparent. Now, in S-I world, it doesn't matter
whether you write:

super().method(arg)

or

MyParent.method(self, arg)

it will just work. But in a M-I world, only the first case will operate
correctly when using multiple inheritance of the particular model for
M-I supported by Python. If your needs are different, you're on your
own, and good luck to you.
Post by Alan Gauld
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,
I think Ben's super()-friendly answer to that would be to use an adaptor
class:


# Untested
class MyCurtain(object):
def __init__(self, *args):
self.__curtain = Curtain(*args)
def __getattr__(self, name):
if name == 'draw':
raise AttributeError
return getattr(self.__curtain, name)
def close(self):
return self.__curtain.draw()


class GraphicalCurtain(Pen, MyCurtain):
def draw(self):
print("Drawing drawing drawing...")
super().draw()
Post by Alan Gauld
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.
There may be tricks you can play with metaclasses, to re-define the
__mro__. You cannot do that with a regular class, as the __mro__
attribute is read-only, but with metaclasses there is no limit to the
deep cacky you can find yourself. Er, I mean, no limit to the wonderful
things you can do.
Post by Alan Gauld
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!)
I think I can agree with that.
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Ben Finney
2015-07-02 23:47:03 UTC
Permalink
Post by Alan Gauld
Post by Ben Finney
Post by Alan Gauld
Whilst 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
As explained on other posts: You're not getting “the superclass” if you
do that. Knowing what the superclass is requires run-time determination
of the MRO.
Post by Alan Gauld
If MyList is included in a MI lattice that doesn't change the fact
that MyList inherits directly from list.
Correct. The distinction being drawn here is between “the class from
which MyList directly inherits” versus “the superclass of this class”.
They are not the same, in multiple inheritance.

To refer to the direct parent class, yes it's simple enough to hard-code
that. But that's not the same thing as accessing the superclass, which
must be determined at run-time.
Post by Alan Gauld
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 “should” is contrary to Python's collaborative multiple inheritance
model. Instead, multiple inheritance in Python entails that any class
should allow the methods of the same name, in all superclasses of this
one, to execute in the sequence determined by ‘super’.

So, if you want behaviour as you describe there, you want something that
Python's mutliple inheritance explicitly won't give you.
--
\ “Intellectual property is to the 21st century what the slave |
`\ trade was to the 16th.” —David Mertz |
_o__) |
Ben Finney

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.pytho
Oscar Benjamin
2015-07-03 16:12:54 UTC
Permalink
Post by Ben Finney
Post by Alan Gauld
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 “should” is contrary to Python's collaborative multiple inheritance
model. Instead, multiple inheritance in Python entails that any class
should allow the methods of the same name, in all superclasses of this
one, to execute in the sequence determined by ‘super’.
So, if you want behaviour as you describe there, you want something that
Python's mutliple inheritance explicitly won't give you.
I guess you mean something that it won't *implicitly* give you. Python
makes it possible to construct whatever method dispatch system you
like in MI but super is designed with the implicit intention that you
would use this particular convention that the same method is called in
all superclasses.

The particular model of multiple inheritance for which super is
designed requires the classes involved to have been designed for that
use case. Simply using super instead of explicitly invoking the
expected superclass does not make a class suitable for this or any
other MI method-calling convention. It is a necessary but not
sufficient condition to make it suitable for the convention you
describe.

You seem to be advocating that "everyone should always use super()
because everyone should always assume that someone else will want to
use their class in a particular style of multiple inheritance setup."
I would rather say that "no one should ever use classes in multiple
inheritance unless the classes involved were designed for that usage
together." (The everyone/always etc. are meant loosely.)

I guess a different point is that it's not really harmful to just use
super() so you may as well "just do it" without giving it much
thought. This argument makes more sense in Python 3 than Python 2
though since 2's super is a little tricky to get right in some cases
(e.g. __new__).

--
Oscar
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listi

Steven D'Aprano
2015-07-02 15:33:25 UTC
Permalink
I mostly agree with what Ben says, comments below.
Post by Ben Finney
Post by Alan Gauld
Whilst 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.
For those who aren't sure, MRO is "Method Resolution Order".

To be precise, all (new style) classes have a MRO:

py> object.__mro__
(<type 'object'>,)

In the multiple-inheritance world, all inheritance is supposed to follow
the MRO, at least by default. It should be quite unusual to manually
bypass the MRO or invent your own, that should stand out as a code
smell.

One complication in Python 2 is that "classic classes" (old style
classes) don't have an explicit MRO. But they do have an implicit one.
Unfortunately classic classes' MRO is buggy when used with multiple
inheritance with a diamond-shaped class hierachy. I won't explain that
unless somebody asks, the important thing to take from this is that you
should try to avoid inheriting from "classic classes" in Python 2.
Post by Ben Finney
Post by Alan Gauld
It'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”.
The 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.
In principle, Ben is correct here, but in practice, multiple-inheritance
in Python is explicitly described as *cooperative* multiple-inheritance.
You cannot expect to take any two (or more) arbitrary classes and
inherit from them both. Sometimes you cannot inherit from them both at
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: multiple bases have instance lay-out conflict


Sometimes you cannot inherit from them both because there is no
consistent MRO, and sometimes you cannot inherit from them both because
they simply don't work well together. In this last case, Python cannot
warn you about it, but your class will just not work right. ("Your save
method over-writes the data my save method just wrote!" sort of thing.)

The simplest way to break M-I is to directly call your parent class by
name, instead of using super(). That effectively guarantees that your
class cannot be used in M-I, except perhaps by accident.

In a nutshell, you can physically inherit from "the" parent class by
explicitly giving the name of the class, but by doing so you are
effectively saying "Uh uh, oh no you don't, no way!" to any one wishing
to use your class in a multiple inheritance situation. As the writer of
the class, that is your right to do so (nobody can force you to write
cooperative M-I classes), but in my opinion it's a bit rude or ignorant,
like writing functions that never return their result but always print
it instead. ("Nobody's going to re-use *my* functions, uh uh, no way!")

(In the M-I world, there is no such thing as "the" parent class. There
is, however, the parent *classes*.)

[...]
Post by Ben Finney
Multiple inheitance is a fact in Python, and good practice is to not
arbitrarily write classes that break it. Hence my advice to avoid
hard-coding the superclass, and only use ‘super’ to discover the
superclass.
I agree that it is good practice to use super, even if you personally
expect to only use single-inheritance. You never know when somebody
else, or even your future self, will decide to use M-I. Don't
unnecessarily cut off that possibility, especially in Python 3 where
using super() is actually easier than explicitly calling the parent
class by hand:

list.append(self, arg)

super().append(arg)


On the other hand, M-I in Python is cooperative, and it's not very often
that you can expect to pick two arbitrary classes and inherit from them
both.

And on the third hand, inheritance in general is often over-rated, and
M-I in particular is hard to get right. There's a strong argument to be
made that one should only use full cooperative M-I when easier, less
powerful versions like mixins and traits aren't enough. Or use
composition and/or delegation instead.
Post by Ben Finney
So please use `super`, even in single inheritance. Otherwise you are
restricting the usefulness of your class: it can never be used with
multiple inheritance.
I cannot disagree with Ben here. Even if you only intend to use single
inheritance, don't unnecessarily rule out the alternatives. Using
super is still usually the right thing to do.
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/
Ben Finney
2015-07-02 23:29:33 UTC
Permalink
Post by Steven D'Aprano
I mostly agree with what Ben says, comments below.
Post by Ben Finney
So please use `super`, even in single inheritance. Otherwise you are
restricting the usefulness of your class: it can never be used with
multiple inheritance.
I cannot disagree with Ben here. Even if you only intend to use single
inheritance, don't unnecessarily rule out the alternatives. Using
super is still usually the right thing to do.
I'm glad you agree with the above, since I was quoting your words from
2011 :-)
--
\ “… no testimony can be admitted which is contrary to reason; |
`\ reason is founded on the evidence of our senses.” —Percy Bysshe |
_o__) Shelley, _The Necessity of Atheism_, 1811 |
Ben Finney

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/
Continue reading on narkive:
Loading...