MRO problems with diamond inheritance?

Discussion in 'Python' started by John Perks and Sarah Mount, May 1, 2005.

  1. 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
    John Perks and Sarah Mount, May 1, 2005
    #1
    1. Advertising

  2. John Perks and Sarah Mount

    M.E.Farmer Guest

    M.E.Farmer, May 1, 2005
    #2
    1. Advertising

  3. John Perks and Sarah Mount

    Robert Dick Guest

    Robert Dick, May 2, 2005
    #3
  4. Michele Simionato, May 2, 2005
    #4
  5. John Perks and Sarah Mount

    M.E.Farmer Guest

    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
    M.E.Farmer, May 2, 2005
    #5
  6. 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/developerworks/linux/library/l-pymeta2/index.html

    Michele Simionato
    Michele Simionato, May 2, 2005
    #6
  7. 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 ;)

    >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
    Michele Simionato, May 2, 2005
    #7
  8. 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
    Michele Simionato, May 2, 2005
    #8
  9. John Perks and Sarah Mount

    M.E.Farmer Guest

    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
    M.E.Farmer, May 2, 2005
    #9
  10. 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/accu2005/pyuk2005_simionato_wondersofpython.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
    Michele Simionato, May 2, 2005
    #10
  11. John Perks and Sarah Mount

    M.E.Farmer Guest

    >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
    M.E.Farmer, May 2, 2005
    #11
  12. John Perks and Sarah Mount

    Aahz Guest

    Use case for multiple inheritance (was Re: MRO problems with diamond inheritance?)

    In article <>,
    Michele Simionato <> 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 () <*> 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."
    Aahz, May 2, 2005
    #12
  13. "Michele Simionato" <> wrote in message
    news:...
    > 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.
    John Perks and Sarah Mount, May 2, 2005
    #13
  14. Re: Use case for multiple inheritance (was Re: MRO problems with diamond inheritance?)

    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
    Michele Simionato, May 3, 2005
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alexander Stippler

    virtual inheritance / dreaded diamond problem

    Alexander Stippler, Jul 14, 2003, in forum: C++
    Replies:
    0
    Views:
    1,870
    Alexander Stippler
    Jul 14, 2003
  2. Alexander Stippler

    virtual inheritance / dreaded diamond again

    Alexander Stippler, Aug 26, 2003, in forum: C++
    Replies:
    1
    Views:
    380
    Ron Natalie
    Aug 26, 2003
  3. Tom
    Replies:
    3
    Views:
    495
  4. Alex Hunsley
    Replies:
    4
    Views:
    357
    Colin J. Williams
    Nov 2, 2005
  5. Ming
    Replies:
    4
    Views:
    654
Loading...

Share This Page