Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python, Overriding an inherited class method

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.

like image 460
d00nut Avatar asked Oct 07 '12 00:10

d00nut


People also ask

How do you override an inherited class in Python?

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.

Can you override inherited methods?

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.

What is meant by method overriding in Python?

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.

What is not true about overriding in Python?

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.


2 Answers

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.

like image 141
unutbu Avatar answered Sep 28 '22 17:09

unutbu


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.

like image 37
Ian Clelland Avatar answered Sep 28 '22 19:09

Ian Clelland