I have two classes, Field
and Background
. They look a little bit like this:
class Field( object ): def __init__( self, a, b ): self.a = a self.b = b self.field = self.buildField() def buildField( self ): field = [0,0,0] return field class Background( Field ): def __init__( self, a, b, c ): super(Background, self).__init__( a, b ) self.field = self.buildField( c ) def buildField( self, c ): field = [c] return field a, b, c = 0, 1, 2 background = Background( a, b, c )
This error is pointing to Field's buildField()
:
"TypeError: buildField() takes exactly 2 arguments (1 given)."
I expected Background init() to be called first. To pass "a, b" to Fields init(), Field to assign a and b then to assign a list with three 0's in it to field. Then for Background's init() to continue, to then call its own buildField() and override self.field with a list containing c.
It seems I don't fully understand super(), however i was unable to find a solution to my issue after looking at similar inheritance problems on the web and around here.
I expected behavior like c++ where a class can override a method that was inherited. How can i achieve this or something similar.
Most issues I found related to this were people using double underscores. My experience with inheritance with super is using the inherited class init() to just pass different variables to the super class. Nothing involving overwriting anything.
In Python method overriding occurs by simply defining in the child class a method with the same name of a method in the parent class. When you define a method in the object you make this latter able to satisfy that method call, so the implementations of its ancestors do not come in play.
A derived class has the ability to redefine, or override, an inherited method, replacing the inherited method by one that is specifically designed for the derived class. The derived class may want to inherit many of the base class's methods because these methods are suited to the behavior of the derived class.
Method overriding is an ability of any object-oriented programming language that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its super-classes or parent classes.
Question 4: What is not true about overriding in Python? Redefining a base class method in the inherited class is called method overriding. Overriding is the essential feature of object-oriented language. The overridden methods must have the same number of arguments as the base class method of the same name.
I expected Background init() to be called. To pass "a, b" to Fields init(), Field to assign a and b
So far, so good.
then to assign a list with three 0's in it to field.
Ah. This is where we get the error.
self.field = self.buildField()
Even though this line occurs within Field.__init__
, self
is an instance of Background
. so self.buildField
finds Background
's buildField
method, not Field
's.
Since Background.buildField
expects 2 arguments instead of 1,
self.field = self.buildField()
raises an error.
So how do we tell Python to call Field
's buildField
method instead of Background
's?
The purpose of name mangling (naming an attribute with double underscores) is to solve this exact problem.
class Field(object): def __init__(self, a, b): self.a = a self.b = b self.field = self.__buildField() def __buildField(self): field = [0,0,0] return field class Background(Field): def __init__(self, a, b, c): super(Background, self).__init__(a, b) self.field = self.__buildField(c) def __buildField(self, c): field = [c] return field a, b, c = 0, 1, 2 background = Background(a, b, c)
The method name __buildField
is "mangled" to _Field__buildField
inside Field
so inside Field.__init__
,
self.field = self.__buildField()
calls self._Field__buildField()
, which is Field
's __buildField
method. While similarly,
self.field = self.__buildField(c)
inside Background.__init__
calls Background
's __buildField
method.
Coming from a C++ perspective, there might be two misconceptions here.
First, a method with the same name and different signature does not overload it like in C++. If one of your Background objects tries to call buildField with no arguments, the original version from Field will not be called -- it has been completely hidden.
The second issue is that if a method defined in the superclass calls buildField, the subclass version will be called. In python, all methods are bound dynamically, like a C++ virtual
method.
Field's __init__
expected to be dealing with an object that had a buildField method taking no arguments. You used the method with an object that has a buildField method taking one argument.
The thing with super
is that it doesnt change the type of the object, so you shouldn't change the signature of any methods that the superclass' methods might call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With