Shahroz Punjwani
Shahroz Punjwani

Reputation: 43

Fundamentals of inheritance in Python

I am trying to understand how inheritance works in python. I was looking at a simple code and one thing is confusing me. The code is following:

class Person:

    def __init__(self, first, last):
        self.firstname = first
        self.lastname = last

    def Name(self):
        return self.firstname + " " + self.lastname

class Employee(Person):

    def __init__(self, first, last, staffnum):
        Person.__init__(self,first, last)
        self.staffnumber = staffnum

    def GetEmployee(self):
        return self.Name() + ", " +  self.staffnumber

x = Person("Marge", "Simpson")
y = Employee("Homer", "Simpson","1007")
print(x.Name()) 
print(y.GetEmployee())

My question is that when are using Person.__init__() to call the constructor of baseclass but when we calling Name() method of base class again, instead of using "Person", we are using "self". Can somebody clear this confusion and me understand the how inheritance works in python?

Upvotes: 3

Views: 173

Answers (3)

Steve Zelaznik
Steve Zelaznik

Reputation: 616

The following two methods are equivalent (assuming the "Name" method is never overridden):

class Employee(Person):
    def __init__(self, first, last, staffnum):
        Person.__init__(self, first, last)
        self.staffnumber = staffnum

    def getEmployee(self):
        return Person.Name(self) + self.staffnumber


class Employee(Person):
    def __init__(self, first, last, staffnum):
        Person.__init__(self, first, last)
        self.staffnumber = staffnum

    def getEmployee(self):
        return self.Name() + self.staffnumber

In the second example, when self.Name() is called, the instance of the class is "bound" to the function, so the first argument doesn't need to be passed.

Because init is being overridden in the Employee subclass, you can't call self.init(first, last). You'll then call Employee.init(self, *args) rather than Person.init(self, *args). This will either create an infinite recursion loop, or you'll get an argument error.

As a general rule, when you're overriding a method, you have to use the following notation in the subclass. ParentClass.methodname(self, *args, **kwargs). The reason you can call self.Name() is because name has not been overridden.

I'm repeating myself here. Does this crystalize it, or have I confused you further?

Upvotes: 1

BrenBarn
BrenBarn

Reputation: 251568

The simple way to say it is that self.method() means "call the most specific implementation of method available" (i.e., the one furthest down the current object's inheritance tree). In this case you don't wall to call self.__init__, because that would call Employee.__init__ again. You need to write Person.__init__ (or use super()) to explicitly call an inherited method.

Because Employee does not define its own Name method, Person.Name is the most specific one available, so that is what is called by self.Name(). If Employee defined its own Name, then that would be called by self.Name() instead.

Upvotes: 0

user2034412
user2034412

Reputation: 4282

The Employee class inherits methods from the base Person class, including the __init__ method. So at the top of the class definition, it has __init__ and Name methods.

Then the Employee class definition overwrites the __init__ method that it inherited. In order to call the __init__ method of Person, it has to call Person.__init__ by name (actually, it could use super() as another alternative).

But since Employee doesn't overwrite the inherited Name method, it can use self.Name() to call the Name method that it inherited at the top.

Upvotes: 2

Related Questions