Inheritance is one of the most powerful features of object-oriented programming languages. It allows us to inherit the functionality from other classes. It is possible to create a new class that modifies the behavior of an existing class through inheritance. Inheritance means that if an object of one class is created by inheriting another class, then the object would have all the functionality, methods, and variables of both the classes; that is, the parent class and new class. The existing class from which we inherit the functionalities is called the parent/base class, and the new class is called the derived/child class.
Inheritance can be explained with a very simple example—we create an employee class with attributes such as name of employee and rate at which he is going to be paid hourly. We can now create a new specialEmployee class inheriting all the attributes from the employee class.
Inheritance in Python is done by passing the inherited class as an argument in the class definition. It is often used to modify the behavior of existing methods.
An instance of the specialEmployee class is identical to an Employee instance, except for the changed hours() method. For example, in the following code we create a new specialEmployee class that inherits all the functionalities of the Employee class, and also change the hours() method:
class specialEmployee(Employee):
def hours(self,numHours):
self.owed += numHours*self.rate*2
return("%.2f hours worked" % numHours)
For a subclass to define new class variables, it needs to define an __init__() method, as follows:
class specialEmployee(Employee):
def __init__(self,name,rate,bonus):
Employee.__init__(self,name,rate) #calls the base classes
self.bonus=bonus
def hours(self,numHours):
self.owed += numHours*self.rate+self.bonus
return("%.2f hours worked" % numHours)
Notice that the methods of the base class are not automatically invoked and it is necessary for the derived class to call them. We can test for the class membership using the built-in isinstance(obj1,obj2) function. This returns True if obj1 belongs to the class of obj2 or any class derived from obj2. Let's consider the following example to understand this, where obj1 and obj2 are the objects of the Employee and specialEmployee classes respectively:
#Example issubclass() to check whether a class is a subclass of another class
#Example isinstance() to check if an object belongs to a class or not
print(issubclass(specialEmployee, Employee))
print(issubclass(Employee, specialEmployee))
d = specialEmployee("packt", 20, 100)
b = Employee("packt", 20)
print(isinstance(b, specialEmployee))
print(isinstance(b, Employee))
# the output prints
True
False
False
True
Generally, all the methods operate on the instance of a class defined within a class. However, it is not a requirement. There are two types of methods—static methods and class methods. A static method is quite similar to a class method, which is mainly bound to the class, and not bound with the object of the class. It is defined within a class and does not require an instance of a class to execute. It does not perform any operations on the instance and it is defined using the @staticmethod class decorator. Static methods cannot access the attributes of an instance, so their most common usage is as a convenience to group utility functions together.
A class method operates on the class itself and does not work with the instances. A class method works in the same way that class variables are associated with the classes rather than instances of that class. Class methods are defined using the @classmethod decorator and are distinguished from instance methods in the class. It is passed as the first argument, and this is named cls by convention. The exponentialB class inherits from the exponentialA class and changes the base class variable to 4. We can also run the parent class's exp() method as follows:
class exponentialA(object):
base=3
@classmethod
def exp(cls,x):
return(cls.base**x)
@staticmethod
def addition(x, y):
return (x+y)
class exponentialB(exponentialA):
base=4
a = exponentialA()
b= a.exp(3)
print("the value: 3 to the power 3 is", b)
print('The sum is:', exponentialA.addition(15, 10))
print(exponentialB.exp(3))
#prints the following output
the value: 3 to the power 3 is 27
The sum is: 25
64
The difference between a static method and a class method is that a static method doesn't know anything about the class, it only deals with the parameters, whereas the class method works only with the class, and its parameter is always the class itself.
There are several reasons why class methods may be useful. For example, because a subclass inherits all the same features of its parent, there is the potential for it to break inherited methods. Using class methods is a way to define exactly what methods are run.