Python, Overriding an inherited class method

d00nut picture d00nut · Oct 7, 2012 · Viewed 71.6k times · Source

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.

Answer

unutbu picture unutbu · Oct 7, 2012

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.