According to Method Resolution Order:
Classic classes used a simple MRO scheme: when looking up a method, base classes were searched using a simple depth-first left-to-right scheme.
This can be verified in Python 2.6
In : import sys In : sys.version Out: '2.6.6 (r266:84292, Jul 23 2015, 15:22:56) \n[GCC 4.4.7 20120313 (Red Hat 4.4.7-11)]' In : class D: def f(self): return 'D' class B(D): pass class C(D): def f(self): return 'C' class A(B, C): pass ...: In : A().f() Out: 'D'
However, I got a different result in Python 2.7.12 if I have defined a metaclass:
Python 2.7.12 (default, Nov 19 2016, 06:48:10) Type "copyright", "credits" or "license" for more information. IPython 5.4.0 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In : class D: # Note: Old-style ...: def f(self): return "D.f()" ...: class B(D): pass ...: class C(D): ...: def f(self): return "C.f()" ...: class A(B, C): pass ...: In : A().f() Out: 'D.f()' # It works as expected. In : class __metaclass__(type): ...: "All classes are metamagically modified to be nicely printed" ...: __repr__ = lambda cls: cls.__name__ ...: In : class D: # Note: Old-style ...: def f(self): return "D.f()" ...: class B(D): pass ...: class C(D): ...: def f(self): return "C.f()" ...: class A(B, C): pass ...: In : A().f() Out: 'C.f()' # WTF??
Metaclasses only apply to new-style classes, and are added by having a field named
__metaclass__ in the class body. Having a
__metaclass__ field causes the class to be a new-style class whether you inherit from
object or not:
class J: pass class K(object): pass class L: __metaclass__ = type type(J) # <type 'classobj'> type(K) # <type 'type'> type(L) # <type 'type'>
So what's happening in your example appears to be that due to lexical/static scoping rules, your metaclass named
__metaclass__ is in scope when the body of class
D is executed the second time. Since Python sees a
__metaclass__ in scope when the body is executed, it uses that as the metaclass for
D and turns it into a new-style class, which changes the method resolution order.
You probably shouldn't be naming a metaclass
__metaclass__. Name it something descriptive like
PrettyPrintClassRepr and apply it to classes when you want it by using
__metaclass__ = PrettyPrintClassRepr in the class body:
class D: __metaclass__ = PrettyPrintClassRepr