Skip to content

Instantly share code, notes, and snippets.

@ionelmc
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ionelmc/6921db37a5d628a54ee8 to your computer and use it in GitHub Desktop.
Save ionelmc/6921db37a5d628a54ee8 to your computer and use it in GitHub Desktop.

T.__init__ doesn't get called, as it's the second last in the mro (because it doesn't inherit Base):

>>> class Base(object):
...         def __init__(self, a):
...                 print 'super chain terminated'
...
>>> class D(Base):
...         def __init__(self, a):
...                 print 'do stuff with', a
...                 super(D, self).__init__(a)
...
>>> class E(Base):
...         def __init__(self, a):
...                 self.a = a
...                 super(E, self).__init__(a)
...
>>> class T(object):
...         def __init__(self, a):
...                 print 'T.__init__'
...
>>> class V5(D, E, T):
...         pass
...
>>> v5 = V5(123)
do stuff with 123
super chain terminated
>>> print v5.a
123
>>> class V6(E, D, T):
...         pass
...
>>> v6 = V6(123)
do stuff with 123
super chain terminated
>>> print v6.a
123

The goal is to write two classes that can be used in multiple inheritance without worying about order of said clases.

>>> class A(object):
...         def __init__(self, a):
...                 self.a = a
...                 super(A, self).__init__(a)
...
>>> class B(object):
...         def __init__(self, a):
...                 print 'do stuff with', a
...
>>> class C(object):
...         def __init__(self, a):
...                 print 'do stuff with', a
...                 super(C, self).__init__(a)
...
>>> class V1(A, B):
...         pass
...
>>> v1 = V1(123)
do stuff with 123
>>> print v1.a
123
>>> class V2(B, A):
...         pass
...
>>> v2 = V2(123)
do stuff with 123
>>> print v2.a # fails, B.__init__ didn't call super()
Traceback (most recent call last):
  File "<ipython-input-11-622b85d68966>", line 1, in <module>
    print v2.a # fails, B.__init__ didn't call super()
AttributeError: 'V2' object has no attribute 'a'
>>> class V3(A, C):
...         pass
...
>>> v3 = V3(123) # fails, object.__init__() takes no parameters
do stuff with 123
Traceback (most recent call last):
  File "<ipython-input-13-92471b2623ee>", line 1, in <module>
    v3 = V3(123) # fails, object.__init__() takes no parameters
  File "<ipython-input-3-927193f9bdcf>", line 4, in __init__
    super(A, self).__init__(a)
  File "<ipython-input-5-5a5c7a030e38>", line 4, in __init__
    super(C, self).__init__(a)
TypeError: object.__init__() takes no parameters
>>> class V4(C, A):
...         pass
...
>>> v4 = V4(123) # fails, object.__init__() takes no parameters
do stuff with 123
Traceback (most recent call last):
  File "<ipython-input-16-0a00995bd35b>", line 1, in <module>
    v4 = V4(123) # fails, object.__init__() takes no parameters
  File "<ipython-input-5-5a5c7a030e38>", line 4, in __init__
    super(C, self).__init__(a)
  File "<ipython-input-3-927193f9bdcf>", line 4, in __init__
    super(A, self).__init__(a)
TypeError: object.__init__() takes no parameters

Heavy handed solution:

>>> class D(object):
...         def __init__(self, a):
...                 print 'do stuff with', a
...                 mro = type(self).__mro__
...                 if D in mro and mro[mro.index(D) + 1:][:1] != (object,):
...                         super(D, self).__init__(a)
...
>>> class E(object):
...         def __init__(self, a):
...                 self.a = a
...                 mro = type(self).__mro__
...                 if E in mro and mro[mro.index(E) + 1:][:1] != (object,):
...                         super(E, self).__init__(a)
...
>>> class V5(D, E):
...         pass
...
>>> v5 = V5(123)
do stuff with 123
>>> print v5.a
123
>>> class V6(E, D):
...         pass
...
>>> v6 = V6(123)
do stuff with 123
>>> print v6.a
123
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment