MRO problems with diamond inheritance?

John Perks and Sarah Mount johnandsarah at estragon.freeserve.co.uk
Sun May 1 18:05:04 EDT 2005


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






More information about the Python-list mailing list