Explicit calls to each base __init__ can be managed by using the following snippet.
# encoding utf8
# py 2.7 / 3.4+
from __future__ import print_function, absolute_import, division
class a(object):
def __init__(self):
print("a")
class b(object):
def __init__(self):
print("b")
class c(object):
def __init__(self):
print("c")
# behavior overrides from right to left
# g -> a -> b -> c
class g(a, b, c):
def __init__(self):
# calling every child __init__ explicitly
print("g")
print(self.__class__.__mro__)
print(self.__class__.__bases__)
# super of self is a
super(self.__class__, self).__init__()
# super of a is b
super(self.__class__.__bases__[0], self).__init__()
# same
# super(a, self).__init__()
# super of b is c
super(self.__class__.__bases__[1], self).__init__()
# same
# super(b, self).__init__()
# super of c object's default __init__ , since it inherited from obj
super(self.__class__.__bases__[2], self).__init__()
# same
# super(c, self).__init__()
# f -> g
class f(g):
def __init__(self):
# overriding and skipping g's __init__
# emulate g's __init__
print("f")
# g
base_t = self.__class__.__bases__[0]
print("f base,", base_t)
# calling g's __init__ directly, in this case would result in infinite recursion since
# base class order has been changed.
# super(self.__class__, self).__init__()
super(base_t, self).__init__()
super(base_t.__bases__[0], self).__init__()
super(base_t.__bases__[1], self).__init__()
super(base_t.__bases__[2], self).__init__()
g()
f()
print(f.__mro__)
print(f.__bases__)
print(f.__name__)
Of course f's implmentation could be turn into a dedicated function for a more elegant solution where the caller only have to specify the appropriate base type.