Skip to content

Instantly share code, notes, and snippets.

@carlos-jenkins
Last active July 7, 2017 22:42
Show Gist options
  • Save carlos-jenkins/21fe92389198d409756890e702ec5d34 to your computer and use it in GitHub Desktop.
Save carlos-jenkins/21fe92389198d409756890e702ec5d34 to your computer and use it in GitHub Desktop.
Collaborative constructors for multiple inheritance.
#!/usr/bin/env python3
"""
Collaborative constructors for multiple inheritance.
Python 3 only. If using Python 2.7, collaborative constructor are broken for
positional arguments.
Collaborative constructors allow classes to collaborate in the way constructor
arguments are passed between all classes in the inheritance tree.
Two aspects are crucial in the constructors:
1. In the signature of the constructors, type:
def __init__(self, [positional arguments], *args, [keyword arguments], **kwargs):
So, make sure you put the *args AFTER the positional arguments, and BEFORE
the keyword arguments.
2. At the end of the constructor, call the constructor of its parent EVEN IF
the parent is the good old object base class, with the remaining positional
and keyword arguments.
Basically, collaborative constructors "consume" their relevant arguments
(positional and keyword) and pass the rest to the other classes in the
inheritance tree.
One final aspect is crucial when defining the multiple inheritance:
1. The call execution is determined by the way you placed the parents.
It WILL run from left to right, depth first.
That is, for example:
class Parent1(object):
pass
class GrandParent(object):
pass
class Parent2(GrandParent):
pass
class Parent3(object):
pass
class MyLeaf(Parent1, Parent2, Parent3):
pass
If you implement collaborative constructors the execution sequence will be:
1. MyLeaf.
2. Parent1.
3. Parent2.
4. GrandParent.
5. Parent3.
When executed, this script will print:
TheClass has arg tcarg1 and kwarg tckwarg1-init
MixinTwo has arg m2arg1 and kwarg m2kwarg1-init
MixinChildOne has arg mc1arg1 and kwarg mc1kwarg1-init
MixinOne has arg m1arg1 and kwarg m1kwarg1-init
ChildOne has arg c1arg1 and kwarg c1kwarg1-init
BaseOne has arg b1arg1 and kwarg b1kwarg1-init
""" # noqa
class BaseOne(object):
def __init__(self, b1arg1, *args, b1kwarg1='b1kwarg1', **kwargs):
self._b1arg1 = b1arg1
self._b1kwarg = b1kwarg1
print('{} has arg {} and kwarg {}'.format(
'BaseOne', b1arg1, b1kwarg1
))
super().__init__(*args, **kwargs)
class BaseTwo(object):
def __init__(self, b2arg1, *args, b2kwarg1='b2kwarg1', **kwargs):
self._b2arg1 = b2arg1
self._b2kwarg = b2kwarg1
print('{} has arg {} and kwarg {}'.format(
'BaseTwo', b2arg1, b2kwarg1
))
super().__init__(*args, **kwargs)
class ChildOne(BaseOne):
def __init__(self, c1arg1, *args, c1kwarg1='c1kwarg1', **kwargs):
self._c1arg1 = c1arg1
self._c1kwarg = c1kwarg1
print('{} has arg {} and kwarg {}'.format(
'ChildOne', c1arg1, c1kwarg1
))
super().__init__(*args, **kwargs)
class MixinOne(object):
def __init__(self, m1arg1, *args, m1kwarg1='m1kwarg1', **kwargs):
self._m1arg1 = m1arg1
self._m1kwarg1 = m1kwarg1
print('{} has arg {} and kwarg {}'.format(
'MixinOne', m1arg1, m1kwarg1
))
super().__init__(*args, **kwargs)
class MixinChildOne(MixinOne):
def __init__(self, mc1arg1, *args, mc1kwarg1='mc1kwarg1', **kwargs):
self._mc1arg1 = mc1arg1
self._mc1kwarg1 = mc1kwarg1
print('{} has arg {} and kwarg {}'.format(
'MixinChildOne', mc1arg1, mc1kwarg1
))
super().__init__(*args, **kwargs)
class MixinTwo(object):
def __init__(self, m2arg1, *args, m2kwarg1='m2kwarg1', **kwargs):
self._m2arg1 = m2arg1
self._m2kwarg1 = m2kwarg1
print('{} has arg {} and kwarg {}'.format(
'MixinTwo', m2arg1, m2kwarg1
))
super().__init__(*args, **kwargs)
class TheClass(MixinTwo, MixinChildOne, ChildOne, BaseOne):
def __init__(self, tcarg1, *args, tckwarg1='tckwarg1', **kwargs):
self._tcarg1 = tcarg1
self._tckwarg1 = tckwarg1
print('{} has arg {} and kwarg {}'.format(
'TheClass', tcarg1, tckwarg1
))
super().__init__(*args, **kwargs)
tc = TheClass(
# Positional arguments must be passed as left to right, depth first.
'tcarg1',
'm2arg1',
'mc1arg1',
'm1arg1',
'c1arg1',
'b1arg1',
# Keyword arguments can be passed in any order.
tckwarg1='tckwarg1-init',
m2kwarg1='m2kwarg1-init',
mc1kwarg1='mc1kwarg1-init',
m1kwarg1='m1kwarg1-init',
c1kwarg1='c1kwarg1-init',
b1kwarg1='b1kwarg1-init',
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment