I've been doing research on Python 3 (my code sample uses 3.7.2) and how to properly use super()
when a class inherits more than one class.
I've read this page, and this page and this article. I think the problem is that the SO links are for an older version of Python, while the article is for Python 3, but it's still confusing.
Suppose I had the following code (don't worry if you think that the relationship can be modeled better, this is just an example to illustrate my problem):
class Weapon:
def __init__(self, name, damage):
self.name = name
self.damage = damage
class Reloadable:
def __init__(self, amount):
self.amount = amount
class Sniper(Weapon, Reloadable):
def __init__(self, name, damage, amount, scope_type):
super().__init__(name, damage)
super().__init__(self, amount)
self.scope_type = scope_type
def adjust_scope(self):
print("Adjusting my scope")
Main:
gun = Sniper("Standard Sniper", 10, 20, "small")
gun.adjust_scope()
print(Sniper.__mro__)
and the MRO
:
(<class 'inheritnacewithsuper.Sniper'>,
<class 'inheritnacewithsuper.Weapon'>,
<class 'inheritnacewithsuper.Reloadable'>, <class 'object'>)
The code works and called the desired parent classes, but I want to make sure, when using Python 3.7, and super()
, is doing super().__init__(name, damage)
and super().__init__(self, amount)
, the correct way to initialize the parent constructors?
The article doesn't do that, instead it called the super()
for only one class (RightPyramid(Square, Triangle)
).
I just want to make sure I'm on the right track, and using proper practices.
super()
requires your code cooperates. Your Weapon
and Reloadable
classes don't, so you actually don't want to use super()
here. You'd call the unbound methods directly on those base classes:
class Sniper(Weapon, Reloadable):
def __init__(self, name, damage, amount, scope_type):
Weapon.__init__(self, name, damage)
Reloadable.__init__(self, amount)
self.scope_type = scope_type
Without super()
, the __init__
methods are unbound so you need to pass in self
explicitly.
See super() considered super! by Python core developer Raymond Hettinger (or the Python conference presentation of the same name for a great overview how to use super()
in a cooperative manner.
To be fully cooperative, all classes in your hierarchy should pass on the super().<methodname>()
calls in the chain of classes. With mix-in classes like Reloadable
, you'd want to either use a base no-op class or handle errors when calling super().__init__()
, or pass on arguments as keyword arguments, and have each __init__()
method accept arbitrary keyword arguments to pass on again:
class Weapon:
def __init__(self, name, damage, **kwargs):
self.name = name
self.damage = damage
# pass on any remaining arguments
super().__init__(**kwargs)
class Reloadable:
def __init__(self, amount, **kwargs):
self.amount = amount
# pass on any remaining arguments
super().__init__(**kwargs)
class Sniper(Weapon, Reloadable):
def __init__(self, name, damage, amount, scope_type):
self.scope_type = scope_type
super().__init__(name=name, damage=damage, amount=amount)
def adjust_scope(self):
print("Adjusting my scope")