Python 3x Pandas Django

Inheritance


One of the major benefits of OOPS is reuse of code and one of the ways this is achieved is through the inheritance mechanism. Inheritance can be best imageined as implementing a type and subtype relationship between classes.

Inheritance allows us to define a class that inherits all the methods and properties from another class.

a. Parent class is the class being inherited from, also called super\base class.

b. Child class is the class that inherits from another class, also called derived class.

Syntax

class parent:
    statements

class child(parent):
    statements

Suppose you want to write a program which has to keep track of the teachers and students in a college. They have some common characteristics such as name, age and address. They also have specific characteristics such as salary, courses and leaves for teachers and, result and fees for students.

You can create two independent classes for each type and process them by adding a new common characteristic would mean adding to both of these independent classes. This quickly becomes unwieldy.

A better way would be to create a common class called SchoolMember and then have teacher and student classes inherit from this class i.e, They will become sub-types of this type (class) and then we can add specific characteristics to these sub-types.

Advantage

There are many advantages to this approach. If we add/chnage any functionality in SchoolMember, this is automatically reflected in the subtypes as well.

For example, you can add a new ID card field for both teacher and students by simply adding it to the SchoolMember class. However, changes in the subtypes do not affect other subtypes.

Another advantage is that if you can refer to a teacher or student object as a SchoolMember object which could be useful is some situations such as counting of the number of school members. This is called polymorphism where a sub-type can be substituted in any situation where a parent type is expected i.e. the object can be treated as an instance of the parent class.

Also observe that we resue the code of the parent class and we do not need to repeat it in the different classes as we would have had used independent classes.

The SchoolMember class in this situation is known as the base class or the superclass. The Teacher and Student classes or subclasses. We will now see this example as a program.

Example - Parent\Super\Base Class

Create a class named Teacher, with firstname and lastname properties, and a printname method

class SchoolMember:
  def __init__(self, firstname, lastname):
    self.firstname = firstname
    self.lastname = lastname

  def printname(self):
    print(self.firstname, self.lastname)

Sub\Child\Derived Class

Create a class named Student, which will inherit the properties and methods from the Teacher class by passing the parent class(Teacher) as a parameter

and then, the Student class has the same properties and methods as the Teacher class.

Use the Teacher & Student class to create an object, and then execute the printname method:

class Teacher(SchoolMember):
  pass
class Student(SchoolMember):
  pass

obj1 = Teacher("John", "Michael")
obj1.printname()            #Output: John Michael

Obj2 = Student("Michael", "Obama")
Obj2.printname()             #Output: Michael Obama

Add __init__() function to the child Class -Student

The __init__() function is called automatically every time the class is being used to create a new object.

class Teacher(SchoolMember):
    def __init__(self, firstname, lastname):

class Student(SchoolMember):
    def __init__(self, firstname, lastname):

When you add the __init__() function, the child class will no longer inherit the parent's __init__() function and it's overrides the inheritance of the parent's __init__() function.

And, to keep the inheritance of the parent's __init__() function, add a call to the parent's __init__() function

class Teacher(SchoolMember):
    def __init__(self, firstname, lastname):
        SchoolMember.__init__(self, firstname, lastname)

class Student(SchoolMember):
    def __init__(self, firstname, lastname):
        SchoolMember.__init__(self, firstname, lastname)

Add Properties

class Teacher(SchoolMember):
    def __init__(self, firstname, lastname, salary):
        SchoolMember.__init__(self, firstname, lastname)
        self.teacher_salary = salary

class Student(SchoolMember):
    def __init__(self, firstname, lastname, student_result):
        SchoolMember.__init__(self, firstname, lastname)
        self.student_result = student_result

Add Methods

class Teacher(SchoolMember):
    def __init__(self, firstname, lastname, salary):
        SchoolMember.__init__(self, firstname, lastname)
        self.teacher_salary = salary
    def salary(self):
        print(self.firstname, self.lastname, "Salary is", self.teacher_salary)

class Student(SchoolMember):
    def __init__(self, firstname, lastname, student_result):
        SchoolMember.__init__(self, firstname, lastname)
        self.student_result = student_result
    def result(self):
        print(self.firstname, self.lastname, self.student_result ,"in this academic year")

teacher1 = Teacher("John", "Michael", "1000$")
teacher1.printname()
teacher1.salary()

student1 = Student("Michael", "Jackson", "Passed")
student1.printname()
student1.result()

Output:

John Michael
John Michael Salary is 1000$
Michael Jackson
Michael Jackson Passed in this academic year

Note:If you add a method in the child class with the same name as a function in the parent class, the inheritance of the parent method will be overridden.

super() Function

super() builtin function returns a proxy object (temporary object of the superclass) that allows us to access methods of the base class and this function will make the child class inherit all the methods and properties from its parent.

class Teacher(SchoolMember):
    def __init__(self, firstname, lastname, salary):
        super().__init__(firstname, lastname) #SchoolMember.__init__(firstname, lastname)
        self.teacher_salary = salary
    def salary(self):
        print(self.firstname, self.lastname, "Salary is", self.teacher_salary)

class Student(SchoolMember):
    def __init__(self, firstname, lastname, student_result):
        super().__init__(firstname, lastname) ##SchoolMember.__init__(firstname, lastname)
        self.student_result = student_result
    def result(self):
        print(self.firstname, self.lastname, self.student_result ,"in this academic year")

teacher1 = Teacher("John", "Michael", "1000$")
teacher1.printname()
teacher1.salary()

student1 = Student("Michael", "Jackson", "Passed")
student1.printname()
student1.result()

Output:

John Michael
John Michael Salary is 1000$
Michael Jackson
Michael Jackson Passed in this academic year

isinstance()

It is a python built-in function and it returns True if the specified object is of the specified type, otherwise False.

Syntax:

isinstance(instance, class)

Example:

class SchoolMember:
  def __init__(self, firstname, lastname):
    self.firstname = firstname
    self.lastname = lastname

  def printname(self):
    print(self.firstname, self.lastname)

class Teacher(SchoolMember):
    def __init__(self, firstname, lastname, salary):
        super().__init__(firstname, lastname)
        self.teacher_salary = salary
    def salary(self):
        print(self.firstname, self.lastname, "Salary is", self.teacher_salary)

class Student(SchoolMember):
    def __init__(self, firstname, lastname, student_result):
        super().__init__(firstname, lastname)
        self.student_result = student_result
    def result(self):
        print(self.firstname, self.lastname, self.student_result ,"in this academic year")

teacher1 = Teacher("John", "Michael", "1000$")
student1 = Student("Michael", "Jackson", "Passed")

# is teacher1 is instance of Teacher ? Yes
print(isinstance(teacher1, Teacher))        #Output: True

# is teacher1 is instance of SchoolMember ? Yes
print(isinstance(teacher1, SchoolMember))   #Output: True

# is teacher1 is teacher1 of object ? Yes
print(isinstance(teacher1, object))         #Output: True

# is student1 is teacher1 of Teacher ? No
print(isinstance(student1, Teacher))        #Output: False

# is student1 is student1 of Student ? True
print(isinstance(student1, Student))        #Output: True

# is student1 is student1 of SchoolMember ? True
print(isinstance(student1, SchoolMember))   #Output: True

# is student1 is student1 of object ? True
print(isinstance(student1, object))         #Output: True

In the above example, teacher1 is instance of Teacher, SchoolMember (as Teacher is subclass of SchoolMember), Object (In python, everthing in python inherit from the base object class that pyton comes with and it's called Object).

In python, every class inherits from base class Object. For example,

class SchoolMember(object):
  def __init__(self, firstname, lastname):
    self.firstname = firstname
    self.lastname = lastname

  def printname(self):
    print(self.firstname, self.lastname)

Introspection

Introspection is ability to determine the type of an object at runtime. Everything in python is an object. We can introspect and examine the object. Every object in Python may have attributes and methods.

Code Introspection is used for examining the classes, methods, objects, modules, keywords and get information about them so that we can utilize it. By using dir(), you can introspect and examine the object.

teacher1 = Teacher("John", "Michael", "1000$")
student1 = Student("Michael", "Jackson", "Passed")

print(dir(student1))

Output:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'firstname', 'lastname', 'printname', 'salary', 'teacher_salary']

If you have any doubts or queries related to this chapter, get them clarified from our Python Team experts on ibmmainframer Community!