Reputation:
I have an abstract base class Bicycle
:
from abc import ABC, abstractmethod
class Bicycle(ABC):
def __init__(self, cadence = 10, gear = 10, speed = 10):
self._cadence = cadence
self._gear = gear
self._speed = speed
@abstractmethod
def ride(self):
pass
def __str__(self):
return "Cadence: {0} Gear: {1} Speed: {2}".format(self._cadence,
self._gear, self._speed)
and a subclass MountainBike
:
from Bicycle import Bicycle
class MountainBike(Bicycle):
def __init__(self):
super().__init__(self)
def ride(self):
return "Riding my Bike"
The following code will cause a recursion error, but if I remove self
from the super().__init__(self)
, the call to __str__(self):
works.
Question:
I only discovered this error when I implemented the __str__(self):
In Python 3.x when calling the parent constructor from the child with no arguments, is passing self
, necessary?
Suppose MountainBike
now sets the cadence
, gear
, speed
this means in my subclass the constructor will look like this:
class MountainBike(Bicycle):
def __init__(self, cadence, gear, speed):
super().__init__(cadence,gear,speed)
notice, self
isn't being passed in the super
because to my knowledge, it can throw the variable assignments off. Is this assumption correct?
Upvotes: 6
Views: 124
Reputation: 19352
self
is passed implicitly to the super call, so adding it explicitly sends it twice:
def __init__(self):
super().__init__(self)
That ends up calling Bicycle(self, self)
, which is the same as Bicycle(self, cadence=self)
.
Later on, you have probably tried convert your instance to str
(e.g. to print it), so this was called:
def __str__(self):
return "Cadence: {0} Gear: {1} Speed: {2}".format(self._cadence,
self._gear, self._speed)
That code tried to convert self._cadence
to a string and self._cadence
is self
because of the previous error, so it continues in an endless recursion (until the recursion exception).
Note that super()
takes two forms: with arguments and without arguments, so there are two correct ways to fix the code.
The Python 3 way (without arguments):
def __init__(self):
super().__init__()
The old Python 2 way, which is more explicit:
def __init__(self):
super(MountainBike, self).__init__()
Both do the same, i.e. they give you the bound __init__
method which already has the implicit self
.
See also here: https://docs.python.org/3/library/functions.html#super
Upvotes: 3