understanding the mro (long)

  • Thread starter Rolando Espinoza La Fuente
  • Start date
R

Rolando Espinoza La Fuente

TL;DR: if you want to stay sane, don't inherit two classes that share
same inheritance graph

I recently got puzzled by a bug from a legacy lib (ClientForm)
which have this code:

class ParseError(sgmllib.SGMLParseError,
HTMLParser.HTMLParseError,
):
pass

And fails because takes __init__ from sgmllib and __str__ from HTMLParser
where __str__ uses attributes set by HTMLParser's init.

At first look, I thought was just matter to swap the inherit classes.
But a deeper
look take me to the python's mro reading:
http://www.python.org/download/releases/2.3/mro/

And to reproduce the error I code this:

class Foo(object):
def __init__(self, msg):
self.msg = msg

def __str__(self):
return 'Foo: ' + self.msg

class Bar(Exception):
def __init__(self, msg):
self.msg = msg

def __str__(self):
return 'Bar: ' + self.msg

class A(Exception):
pass

class B(RuntimeError):
pass

class AFoo(A, Foo): pass
class ABar(A, Bar): pass

class BFoo(B, Foo): pass
class BBar(B, Bar): pass

print AFoo('ok') # ok
print ABar('ok') # Bar: ok

print BFoo('ok') # ok
print BBar('fail') # AttributeError: ... not attribute 'msg'

# EOF

After running the code I was still confused. So I read carefully again
the mro stuff. And ended doing this inheritance tree:

object (__init__, __str__)
| \
| Foo (__init__, __str__)
|
BaseException (__init__, __str__)
|
|
|
Exception (__init__)
/ | \
A | Bar (__init__, __str__)
|
StandardError (__init__)
|
|
|
RuntimeError (__init__)
/
B

Then I figure out the method resolution following the inheritance graph:
* AFoo(A, Foo):
__init__ from Exception
__str__ from BaseException

* ABar(A, Bar):
__init__ from Bar
__str__ from Bar

* BFoo(B, Foo):
__init__ from RuntimeError
__str__ from BaseException

* BBar(B, Bar):
__init__ from RuntimeError
__str__ from Bar


Finally everything make sense. And make think about be careful when
doing multiple inheritance.

Any thoughts?

~Rolando
 
S

Steven D'Aprano

TL;DR: if you want to stay sane, don't inherit two classes that share
same inheritance graph

I recently got puzzled by a bug from a legacy lib (ClientForm) which
have this code: [...]
Finally everything make sense. And make think about be careful when
doing multiple inheritance.

Any thoughts?


Wow. Nice work, thanks for taking the time for documenting this publicly.
 
M

Michele Simionato

Finally everything make sense. And make think about be careful when
doing multiple inheritance.

Any thoughts?

~Rolando

I am not fond of multiple inheritance either and I wrote at length
about the dangers of it. If you do not know it already, you may be
interested in reading my "Mixins considered harmful" series
http://www.artima.com/weblogs/viewpost.jsp?thread=246341 (together
with any blog posts on super and related subjects).
 
C

Carl Banks

TL;DR: if you want to stay sane, don't inherit two classes that share
same inheritance graph
[snip rest]


If you want to stay sane, don't inherit from ANY class unless

A. you own it, or
B. it's explicitly documented as supporting inheritance

Furthermore, if you want to stay sane, don't mulitply inherit from any
class unless

A. you own it, or
B. it's explicitly documented as supporting MULTIPLE inheritance


Inheritance is always risky if you don't know what you're inheriting
from.


Carl Banks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,076
Latest member
OrderKetoBeez

Latest Threads

Top