I've converted your code to Python3 (by changing print to print()) and added some more tracing statements:
class A(object):
def __init__(self):
print("A", type(self).__mro__)
super(A, self).__init__()
print("/A")
class B(object):
def __init__(self):
print("B", type(self).__mro__)
super(B, self).__init__()
print("/B")
class C(A,B):
def __init__(self):
print("C")
A.__init__(self)
print("ca/b")
B.__init__(self)
print("/C")
C()
Here's the output:
C
A (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
B (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
/B
/A
ca/b
B (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
/B
/C
Looking at the output, you can see the call to the C.__init__ method is happening, and printing 'C'. It then calls A.__init__ directly (which is a mistake- use super!).
The A.__init__ call prints its message, including the __mro__ attribute. You can see the sequence: C -> A -> B -> Object. This is important, because it means that calls to super() from within A.__init__ are going to refer to class B. Also, calls to super from inside C.__init__ would have invoked A.__init__ automatically, if you let them.
The next method, B.__init__, is invoked by the super reference inside A.__init__, as mentioned. It calls Object.__init__, presumably, which prints nothing. ;-)
Both B.__init__ and A.__init__ return, we see the midpoint message ca/b, and then your direct call to B.__init__ is made. It prints a message, but again a reference to super form B.__init__ does nothing, because B is at the tail end of the MRO.
The super() mechanism can deal with all this MRO stuff for you. You shouldn't have to invoke A.__init__(self). Instead, you can just let super handle it, inside C.__init__, but doing this:
class C(A,B):
def __init__(self):
print("C")
super(C, self).__init__()