In this Page, We are Providing Python Programming – Inheritence. Students can visit for more Detail and Explanation of Python Handwritten Notes Pdf.
Python Programming – Inheritence
Inheritence
A class can be based on one or more other classes, called its “base class(es)”. It then inherits the data attributes and methods of its base classes. This is called “inheritance”, and the class which inherits from the base class is called “derived class”. A class definition first evaluates the inheritance list, if present. A simple form of derived class definition looks like this:
class DerivedClassName ( BaseClassName ) : <statement-1> . . . <statement-N>
In place of a base class name BaseClassName, other arbitrary expressions are also allowed. This is useful, for example, when the base class is defined in another module:
class DerivedClassName ( modname . BaseClassName ) :
The following example demonstrates class inheritance.
class Parent: # Base class definition parentAttr=100 def ___init___ ( self ) : print "Base class" def parentMethod ( self ) : print ' Base class method ' def setAttr ( self , attr ) : Parent.parentAttr=attr def getAttr ( self ) : print "Parent attribute : " , Parent . parentAttr class Child ( Parent ) : # Derived class definition def ___init___ ( self ) : print " Derived class " def childMethod ( self ) : print ' Derived class method ' c=Child ( ) c . childMethod ( ) c . parentMethod ( ) c.setAttr ( 200 ) c . getAttr ( )
The output is:
Derived class Derived class method Base class method Parent attribute : 200
Execution of a derived class definition proceeds in the same way as for a base class. If a requested attribute is not found in the class, the search proceeds to look in the base class. This rule is applied recursively if the base class itself is derived from some other class.
The following example is a step further in understanding inheritance.
class Person : population=0 def ___init___ ( self , Name , Age ) : self . name=Name self . age=Age Person . population+=1 def Record ( self ) : print ( ' Name : " { 0 } " Age : { 1 }" ' . format ( self . name , self . age ) ) class Employee ( Person ) : def ___init___ ( self , Name , Age , Salary ) : Person. ___init___ ( self , Name , Age ) self . salary=Salary print ( ' Entered record for { 0 } ' . format ( self . name ) ) def Record ( self ) : Person . Record ( self ) print ( ' Salary : " { 0 : d } " ' . format ( self . salary ) ) class Employer ( Person ) : def ___init___ ( self , Name , Age , Percentage ) : Person. ___init___ ( self , Name , Age ) self . percentage=Percentage print ( 'Entered record for { 0 } ' .format ( self . name ) ) def Record ( self ) : Person . Record ( Self ) print ( ' Partnership percent : "{ 0 : d }" ' . format ( self . percentage ) ) employee1=Employee ( ' Ram ', 26 , 25000 ) employee2=Employee ( ' Ahmed ' , 20 , 50000 ) employee3=Employee ( ' John ' , 22 , 75000 ) employer1=Employer ( ' Michael ' , 58 , 60 ) employer2=Employer ( ' Kishah ' , 52 , 40) members=[employee1 , employee2 , employee3 , employer1,employer2] for member in members : member . Record ( )
The output is:
Entered record for Ram Entered record for Ahmed Entered: record for John . Entered record for Michael Entered record for Kishan Name : " Ram " Age : " 26 " Salary : " 25000 " Name : " Ahmed " Age : " 20 " Salary : " 50000 " Name : " John " Age : " 22 " Salary : " 75000 " Name : "Michaei " Age : " 58 "' Partnership percent : " 60 " Name : " Kishan " Age : " 52 " Partnership percent : " 40 "
Please note that, if a base class has an ___init___ ( ) method, the derived class’s ___init___ ( ) method, if any, must explicitly call it, to ensure proper initialization of the base class part of the instance; for example : BaseClass. ___init____ ( self , [ args . . . ] ).
New-style and classic classes
Classes and instances come in two flavors: old-style (or classic) and new-style. New-style classes were introduced in Python 2.2. For compatibility reasons, classes are still old-style by default. Any class which inherits from object is a new-style class. The object class is a base for all new style classes. The following is an example showing simple definitions of old-style and new-style classes.
>>> class ClassicExample : . . .        def ___init___ ( self ) : . . .        pass . . . >>> class NewStyleExample ( object ) : . . .        def ___init___ ( self ) : . . .            pass . . . >>>
Overriding Methods
Derived classes may override methods of their base classes. A method of a base class that calls another method defined in the same base class may end up calling a method of a derived class that overrides it.
# InheritenceExample2 . py class Parent :Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â # Base class definition def printlnfo ( self ) : Â Â Â Â Â Â Â Â Â print ' Base class method ' def parentMethod ( self ) : Â Â Â Â Â Â Â Â Â Â self . printlnfo ( ) class Child ( Parent ) :Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â # Derived class definition def printlnfo ( self ) : Â Â Â Â print ' Derived class method ' c=Child ( ) c . parentMethod ( )
The output is:
Derived class method
It can be seen that printlnfo ( ) of derived class is called instead of base class.
Super ( ) function
The is a built-in function super ( ), which can be used for accessing inherited methods that have been overridden in a class. The super ( ) only works for new-style classes; in a class hierarchy with single inheritance, super can be used to refer to parent classes without naming them explicitly, thus making the code more maintainable.
class Parent ( object ) :Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â # Base class definition def printlnfo ( self ) : Â Â Â Â Â Â print ' Base class method ' Â Â Â Â Â Â def parentMethod ( self ) : Â Â Â Â Â Â self . printlnfo ( ) class Child ( Parent ) :Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â # Derived class definition def printinfo ( self ) : Â Â Â Â Â Â Â super ( Child , self ) . printlnfo ( ) #Â Â Â Â Â Â Parent . printlnfo ( self ) Â Â Â Â Â Â Â print ' Derived class method ' e=Child ( ) c . parentMethod ( )
The output is:
Base class method Derived class method
In the above example, to access the printlnfo ( ) method of Parent class, super ( ) method in the form of super (Child, self) .printlnfo () is used, where the name of base class is not mentioned. The other way would have been by using Parent .printlnfo (self).
Name mangling
In Python, there is a mechanism called “name mangling” to avoid name clashes of names in class with names defined by sub-classes. Any identifier of the form ____spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname___ spam, where classname is the current class name. Note that, the mangling rule is designed mostly to avoid accidents.
# InheritenceExample3 . py Class Parent :Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â # Base class definition def ___printlnfo ( self ) : Â Â Â Â Â print ' Base class method ' def parentMethod ( self ) : Â Â Â Â Â Â Â self. ___print Info ( ) class Child (Parent) :Â Â Â Â Â Â Â Â Â Â Â Â Â # Derived class definition def printlnfo ( self ) : Â Â Â Â Â print ' Derived class method ' c=Child ( ) print Parent. ___diet___ . keys ( ) print Child. ___diet___ . keys ( ) c . parentMethod ( ) c ._Child___printlnfo ( ) c . _Parent___printlnfo ( )
The output is:
[ ' ____module___ ' , ___Parent___printlnfo ' , ' ____doc___ ' , ' parentMethod ' ] [' ____module ____ ' , ' ___doc____ ' , ' ___Child____printlnfo ' ] Base class method Derived class method Base class method
Multiple inheritence
Till now, the discussion was about inheriting from one class; this is called “single inheritance”. Python also supports “multiple inheritance”, where a class can inherit from more than one class. A simple class definition inheriting from multiple base classes looks like:
class DerivedClassName ( Base1 , Base2 , Base3 ) : <statement-1> . . . <statement-N>
Whenever there is a call via DerivedClassName class instance, Python has to look-up the possible function in the class hierarchy for Basel, Base2 , Base3 , but it needs to do this in a consistent order. To do this, Python uses an approach called “method resolution order” (MRO) using an algorithm called “C3” to get it straight.
Consider the following multiple inheritance example.
class A ( object ) : Â Â Â Â def printlnfo ( self ) : Â Â Â Â Â print ' Class A ' class B ( A ) : Â Â Â Â def printlnfo ( self ) : Â Â Â Â print ' Class B ' #Â Â Â super ( B , self ) . printlnfo ( ) Â Â Â Â A . printlnfo ( self ) class C ( A ) : Â Â Â Â Â def printlnfo ( self ) : Â Â Â Â Â print ' Class C ' Â Â Â Â Â super ( C , self ) . printlnfo ( ) class D ( B , C ) : Â Â Â Â def printlnfo ( self ) : Â Â Â Â print ' Class D ' Â Â Â Â super ( D , self ) . printlnfo ( ) foo=D ( ) foo . printInfo ( )
Running the code yield the following output.
Class D Class B Class A
It can be observed that C class printlnfo ( ) is skipped. The reason for that is because B class printlnfo ( ) calls A class printlnfoO directly. The purpose of super ( ) is to entertain method resolution order. Now un-comment super (B, self) .printlnfoO and comment-out A. print Info (self). The code now yields a different result.
Class D Class B Class C Class A
Now all the printinfo ( ) methods get called. Notice that at the time of defining B. print Info ( ), one can think that super (B, self) .printlnfo ( ) is the same as calling A. print Info (self), however, this is wrong. In the above situation, super (B, self). print Info ( ) actually calls C . printInfo ( self ).