I find that many classes I write in Python contain a small set of variables I actually would like to see when I call str()
, and that rewriting __str__(self)
for each is rather cumbersome. Thus, I cooked up the following mixin,
class StrMixin(object):
'''
Automatically generate __str__ and __repr__
'''
def __str__(self):
import types
name = self.__class__.__name__ + ': '
attrs = [ '{}={}'.format(k,v) for (k,v) in self.__dict__.items() ]
return name + ', '.join(attrs)
def __repr__(self):
return str(self)
However, if I write a class,
class C(object, StrMixin):
pass
I get the following error on instantiation,
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases object, StrMixin
Granted, including object
here is redundant, but what's really going on here?
Method Resolution Order (MRO) is an algorithm for the construction of linearization - the list of all the ancestors of a class, including the class itself, ordered from the closest to the furthest. This is the order in which methods and attributes are looked up.
In Python, so-called mixins are classes that live in the normal inheritance tree, but they are kept small to avoid creating hierarchies that are too complicated for the programmer to grasp. In particular, mixins shouldn't have common ancestors other than object with the other parent classes.
To get the MRO of a class, you can use either the __mro__ attribute or the mro() method. The __mro__ attribute returns a tuple, but the mro() method returns a python list. To take a more complex example that also demonstrates depth-first search, we take 6 classes. We can represent this with the following diagram.
Method Resolution Order(MRO) it denotes the way a programming language resolves a method or attribute. Python supports classes inheriting from other classes. The class being inherited is called the Parent or Superclass, while the class that inherits is called the Child or Subclass.
When you define:
class StrMixin(object):
...
The compiler knows that StrMixin
comes before object
in the class's MRO.
When you do:
class C(object, StrMixin):
pass
You have told the compiler that object
comes before StrMixin
in the MRO. But object
also has to come after StrMixin
so it would have to appear twice in the MRO and that isn't allowed.
If you say:
class C(StrMixin, object):
pass
then the MRO is simply C
, StrMixin
, object
which satisfies the ordering imposed by both classes. There is no duplication because although object
is referenced twice there is no conflict between the definitions.
You answered the question yourself - the second object
is redundant. Class C has two bases: object and StrMixin. However, StrMixin's base is also object, so its gets confused as to which object it should resolve first. The MRO is calculates it as (C, STRMixin, object, object), which has duplicate objects. In this particular case it seems obvious what the solution should be, but add a few more classes and the MRO could become much less clear. E.g.
class A(object):
pass
class B(object, A):
pass
class C(object, A):
pass
class D(object, B, C):
pass
class E(object, A, D):
pass
What is the MRO for E? Whatever it is, its really complicated, has duplicates and probably a few loops.
MRO is explained quite well here, and your specific case is dealt with about two thirds down the page, the first example under "Bad Method Resolution Orders".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With