By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,732 Members | 1,388 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,732 IT Pros & Developers. It's quick & easy.

MRO problems with diamond inheritance?

P: n/a
Trying to create the "lopsided diamond" inheritance below:
class B(object):pass
class D1(B):pass
class D2(D1):pass
class D(D1, D2):pass Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases D1, D2

Is this as intended? Especially since reversing the order makes it OK:
class D(D2, D1):pass
D.__mro__

(<class '__main__.D'>, <class '__main__.D2'>, <class '__main__.D1'>,
<class '__m
ain__.B'>, <type 'object'>)

Why should order of base classes matter? This only affects types,
old-style classes are unaffected.

The workaround to this problem (if it is a problem and not a feature
that I'm misunderstanding) is to put more-derived classes at the front
of the list. I ran into this with dynamically-created classes, and
sorting the bases list with the following comparator put them right:

def cmpMRO(x,y):
if x == y:
return 0
elif issubclass(x, y):
return -1
elif issubclass(y, x):
return +1
else:
return cmp(id(x), id(y))

Incidentally, is it safe to have an mro() method in a class, or is this
as reserved as the usual __reserved_words__? Does Python use mro() (as
opposed to __mro__) internally or anything?

Thanks

John

Jul 19 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a
Your answer lies somewhere in this page ;)
http://www.python.org/2.2.2/descrintro.html
M.E.Farmer

Jul 19 '05 #2

P: n/a
M.E.Farmer:
Your answer lies somewhere in this page ;)
http://www.python.org/2.2.2/descrintro.html
M.E.Farmer


delegate.py (use PyPI) may also be useful.

-Robert Dick-
Jul 19 '05 #3

P: n/a
> M.E.Farmer:
Your answer lies somewhere in this page ;)
http://www.python.org/2.2.2/de*scrintro.html


Yes, when it refers to

http://www.python.org/2.3/mro.html

(section Bad Method Resolution Orders).

In short, it is a feature, not a bug.

Michele Simionato

Jul 19 '05 #4

P: n/a
I knew it was a feature but had only a few minutes to answer and was
playing it safe ;)
You would be surprised how many answers you can squeeze out of that one
URL.
That whole page is worth a month of study( for me anyway ).
I am still trying to grasp the 'purpose' of classmethods.

Michele Simionato wrote:
M.E.Farmer:

Your answer lies somewhere in this page ;)
http://www.python.org/2.2.2/de*scrintro.html


Yes, when it refers to

http://www.python.org/2.3/mro.html

(section Bad Method Resolution Orders).

In short, it is a feature, not a bug.

Michele Simionato


Jul 19 '05 #5

P: n/a
John & Sarah:
Incidentally, is it safe to have an mro() method in a class, > or is this as reserved as the usual __reserved_words__? Does Python > use mro() (as opposed to __mro__) internally or anything?


..mro() is a metamethod, it is a method of the metaclass, not of the
class. So you can override it without problems, and still access it as
type.mro(cls).

For more about metamethods see
http://www-128.ibm.com/developerwork...ta2/index.html

Michele Simionato

Jul 19 '05 #6

P: n/a
M.E. Farmer:
You would be surprised how many answers you can squeeze out of that oneURL.
That whole page is worth a month of study( for me anyway ).
One month only? You must be pretty smart, one could easily extract
a book from that page ;)
I am still trying to grasp the 'purpose' of classmethods.


In my personal opinion classmethods and staticmethods could (and
possibly
should) be removed from the language; a part for that consideration,
the typical
use for classmethods is as object factories, to provide alternative
constructors.

Michele Simionato

Jul 19 '05 #7

P: n/a
BTW, what it your use case? I have yet to see a single compelling use
case for multiple inheritance, so I am
curious of what your design is.

Michele Simionato

Jul 19 '05 #8

P: n/a
Michele Simionato wrote:
M.E. Farmer:
You would be surprised how many answers you can squeeze out of that

one
URL.
That whole page is worth a month of study( for me anyway ).


One month only? You must be pretty smart, one could easily extract
a book from that page ;)

No, I was being 'conservative'.
I am not as smart as the fellow that wrote that MRO paper ;)
Honestly, I have had that bookmarked for years...
There are some deep conceps on that page and I have not had a 'use
case' for most of them.
I would gladly welcome the book, you gonna write it!?
Something that covers ( with lots of 'real-life' examples ):
classes ( I see a lot of questions on c.l.py about basic class use )
special methods and class customization ( putting classes to work )
metaclasses ( what they are and when you might need them )
inheritance ( covering all flavors subclassing,mixin,etc.. )
descriptors ( what are they and why you should care )
types ( creating new ones, subclassing old ones, etc... )
old style / newstyle gotchas for classes / metaclasses
and maybe a few pages on decorators.

It is all well and good to have advanced OO in the language,
but it would be better if there was a 'reason' for it all.
I am still trying to grasp the 'purpose' of classmethods.


In my personal opinion classmethods and staticmethods could (and
possibly
should) be removed from the language; a part for that consideration,
the typical
use for classmethods is as object factories, to provide alternative
constructors.

Michele Simionato


Thank you, I had a feeling that it was just extra fluff.
But I felt/feel that way about list comprehensions and decorators too
;)
M.E.Farmer

Jul 19 '05 #9

P: n/a
Well, writing that book would be a major undertaking that I am not
willing
to take any soon ;)

However, all you are asking for is already in my lectures at ACCU:
http://www.reportlab.org/~andy/accu2...rsofpython.zip
From the README:


"""
<snip>
Generally speaking these lectures are unpolished, too concise, with
more code than words, and with cutting edge/experimental code.
Read them at your risk and peril. Take in account the fact that they
were prepared as a last minute replacement for Alex Martelli's
tutorial,
with a limited amount of time and a very advanced program to follow.

My main concern in preparing these notes was to give the readers a few
*ideas*, not polished solutions. If you are reading these notes, you
will be more than capable to customize these ideas to your own
situation
and to fix the unavoidable little bugs, imperfections, annoyances.

Whereas I recommend the first lecture about iterators and generators
to everybody, take in account than the second and especially the
third lecture may cause your head to explode. I do not take any
responsability in that case.
"""
Michele Simionato

Jul 19 '05 #10

P: n/a
>Well, writing that book would be a major undertaking that I am not
willing to take any soon ;) Well at least you didn't say NO, so when you DO write the book I will
buy a copy.
However, all you are asking for is already in my lectures at ACCU

How many people can say ' No book just these lectures that cover
everything you want '
I knew I was asking the right person ;)
Now I just need to read your lectures...but first I am going to wrap my
head in duct tape.
( prevents/contains explosions )
Thanks for your time,
M.E.Farmer

Jul 19 '05 #11

P: n/a
In article <11*********************@o13g2000cwo.googlegroups. com>,
Michele Simionato <mi***************@gmail.com> wrote:

BTW, what it your use case? I have yet to see a single compelling use
case for multiple inheritance, so I am curious of what your design is.


Dunno whether you'd call it compelling, but my current company uses
multiple inheritance to compose a mega-class with different methods
depending on what the mega-class's capabilities are. It's a pretty
baroque design, admittedly, but I'm not sure how I'd do it differently
from scratch. We've even implemented our own super() for cooperative
method calls with classic classes.

(This application was started in Python 1.4; we're slowly refactoring
it, but we're still using Python 2.2/2.3 -- we didn't get rid of 1.5.2
until last July. Now you know why I've gotten even more conservative
since I started this job last June...)
--
Aahz (aa**@pythoncraft.com) <*> http://www.pythoncraft.com/

"It's 106 miles to Chicago. We have a full tank of gas, a half-pack of
cigarettes, it's dark, and we're wearing sunglasses." "Hit it."
Jul 19 '05 #12

P: n/a

"Michele Simionato" <mi***************@gmail.com> wrote in message
news:11*********************@o13g2000cwo.googlegro ups.com...
BTW, what it your use case? I have yet to see a single compelling use
case for multiple inheritance, so I am
curious of what your design is.


Before I start, I should mention that my workaround I listed previously
is bogus, but I think this:

listOfBases.sort(reverse=True, key=lambda b:len(b.__mro__))

has the effect of pulling the most derived classes to the front of the
bases list, which at any rate stops the exception being thrown.

My compelling use case for MI in Python is... better to model MI in Java
:)

Well, I'll come back to that. In the "real" world, I have found
single-implementation-multiple-interface inheritance (as presented by
Java and .NET) to be highly expressive while avoiding some of the issues
of multiple-implementation inheritance as presented by C++. (Though I
don't agree with Java's FUD that multpile-implementation iheritance is a
bad design choice simply because Java doesn't support it.) In one
application, we had a simple (tree-like, non-MI) hierarchy of abstract
interfaces which would be used by the API's clients:

class Thing { } // abstract
class SpecialThing : virtual public Thing { } // abstract

and the concrete subclasses (that were not exposed via the API) mirrored
it:
class ThingImpl : virtual public Thing { }
class SpecialThingImpl : virtual public SpecialThing, virtual public
ThingImpl { }

(That said, that same job sent me on a training course to learn not to
use inheritance *at* *all*, but rather cut'n'paste multiple copies of
the same code and maintain them in parallel. I got laid off when it
transpired that the entire project was just a figment of somebody's
imagination.)

I'm currently writing a package to embed Java in Python (another one,
just what the world needs), and I use Python's dynamic type creation to
"grow" a Python type hierarchy mirroring that of the underlying Java
object, which is where I'd been running into the MRO problems that
kicked off this whole thread. The Java classes are represented by Python
types, where the one for class Class is also the metaclass of all the
Java objects. Aside from those though, I've now had to model Java's MI
in both C++ and Python and found it to be surprisingly painless on both
occasions.

(In cas you're interested, it all works via:

[Python client code] --> pyJav(Python) --> Boost.Python -->
pyJav._core(C++) --> MyJNI++ --> JNI --> [Java code]

where all the stuff you've never heard of is mine. I'm aiming to keep
the pyJav C++ layer as thin as possible, and do everything I can in
Python.)

John.
Jul 19 '05 #13

P: n/a
AFAIK, the best use case for multiple inheritance is the plugin
pattern,
when you plug in methods in a class according to a given condition.

For instance:

if plugin == "PDF":
class DocumentGenerator(BaseGenerator, PDFMixin): pass
elif plugin == "PS":
class DocumentGenerator(BaseGenerator, PSMixin): pass
elif plugin == "HTML":
class DocumentGenerator(BaseGenerator, HTMLMixin): pass

etc. This is not a bad use case (actually it is good) still I would say
it
is not compelling. I could just add the right methods by hand:

if plugin == "PDF":
DocumentGenerator = type("DocumentGenerator", (BaseGenerator,),
PDFmethods)
elif plugin == "PS":
DocumentGenerator = type("DocumentGenerator", (BaseGenerator,),
PSmethods)
elif plugin == "HTML":
DocumentGenerator = type("DocumentGenerator", (BaseGenerator,),
HTMLmethods)
or use a different design based on composition + delegation.

The problem with MI is that it does not really give anything new that
you cannot do in other ways (at least in a dynamic language such as
Python); OTOH, it is extremely easily abused and makes difficult to
reason about code. Look to what happened to Zope 2!

Adding methods by hand is ugly, people would think twice before doing
that;
OTOH, using mixin is even worse, still it looks cool and people do not
realize how bad it is. Here I speak for personal experience, as you may

imagine, having both read and written MI hierarchies that could have
much better written without MI. Finally, let me say that cooperative
methods are terrible for maintenance. Nowadays, I tend to use MI just
for debugging (yes, a mixing is convenient, if not compelling, for
adding debugging functionality to a class).
Michele Simionato

Jul 19 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.