Reputation:
I want to use polymorphism and have a Movil
class as my parent class, and while specific class is Car
:
class Movil:
def __init__(self, name):
self._name = name
class Car(Movil):
def __init__(self, code):
super().__init__()
self.code = code
Since every Movil
takes a name and every Movil
takes a code
and is a car, I expect to be able to pass both:
class Main(object):
def main(self):
a=Car('toyota','001')
if __name__ == "__main__":
Main().main()
But I am getting this error:
Traceback (most recent call last):
File "main", line 1, in <module>
File "main", line 3, in main
TypeError: __init__() takes 2 positional arguments but 3 were given
What is wrong with this code?
Upvotes: 1
Views: 1062
Reputation: 50116
TLDR: Method parameters are not "inherited" when a child class overrides a parent method. The child class method must explicitly take and forward the parameter:
class Car(Movil):
def __init__(self, name, code):
super().__init__(name)
self.code = code
Inheritance only integrates attributes and methods of the base class into the child class. Notably, if the child class redefines an attribute or method, this hides ("shadows") the parent attribute/method completely.
For example, if Car
would not define its own __init__
then Movil.__init__
would be used. Related and derived features – such as "the parameters of __init__
" – are not themselves inherited: they only show up because they belong to the inherited attribute/method.
Since Car
does define its own __init__
, this shadows Movil.__init__
including its related features, such as the parameters.
In order for Car
to take the original name
parameter, it must be explicitly re-defined on Car.__init__
:
class Car(Movil):
# v take `name` parameter of Movil.__init__
def __init__(self, name, code):
# v pass on `name` parameter to Movil.__init__
super().__init__(name)
self.code = code
As an alternative, variadic positional (*args
) or keyword (**kwargs
) parameters may be used to forward all unknown arguments:
class Car(Movil):
# v collect unknown arguments
def __init__(self, code, *args, **kwargs):
# v pass on unknown arguments to Movil.__init__
super().__init__(*args, **kwargs)
self.code = code
a = Car("001", "toyota")
b = Car(name="toyota", code="001")
Be mindful that variadic parameters make it difficult or impossible to replicate some patterns using positional-or-keyword parameters. For example, in the above example it is not possible to accept code
as both a keyword or trailing positional argument, as is possible with the explicit definition.
Upvotes: 4