Python Learning Diary Inheritance

Posted by sriphp on Fri, 06 Sep 2019 13:44:37 +0200

inherit

What is inheritance? A derived class inherits the fields and methods of the base class. A class can be inherited by more than one class; in python, a class can inherit more than one class.

Parents can be called base classes and superclasses, while subclasses can be called derived classes.

There are two kinds of inheritance: single inheritance and multiple inheritance.

The following is the usage of inheritance, grammar is'class subclass name (parent class name):'

class Plane:                                    #Define a parent class for all fighters
    def __init__(self,name,speed,hp,atk):
        self.name = name
        self.speed = speed
        self.hp = hp
        self.atk = atk

class Fighter(Plane):                           #Define a Fighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,money):
        self.name = name
        self.speed = speed
        self.hp = hp
        self.atk = atk
        self.money= money
    def Attack(self,enemyFighter):
        enemyFighter.hp -= self.atk

class EnemyFighter(Plane):                      #Define a EnemyFighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,type):
        self.name = name
        self.speed = speed
        self.hp = hp
        self.atk = atk
        self.type = type
    def EnemyAttack(self,fighter):
        fighter.hp -= self.atk

If we want to know who is the parent of a class, we can use the _bases_ method to view it.

print(Plane.__bases__)          #(<class 'object'>,)
print(Fighter.__bases__)        #(<class '__main__.Plane'>,)
print(EnemyFighter.__bases__)   #(<class '__main__.Plane'>,)

It can be seen from the results that both subclasses inherit the parent class Plane, which inherits the'ancestor'object class of the class. In a python 3, all classes have a parent class. If a class does not inherit, its parent class is a subclass of object.

New class: no parent class inherits object class by default

 

Abstract concepts

Abstraction is the extraction of similar or comparative parts.

It can be divided into two levels: extracting the similar parts of two similar objects into classes and extracting the similar parts of multiple classes into parent classes.

Inheritance is based on abstract results. To realize it through programming language, it must first go through the process of abstraction, then the abstract structure can be expressed through inheritance, and the relationship between classes and classes can only be inherited.

 

single inheritance

When we write the above code, we can find that many attributes of Fighter class and EnemyFighter class are duplicated in the parent class, and some attributes are unique to themselves, so we call them derived attributes. Now let's modify our code above:

class Plane:                                    #Define a parent class for all fighters
    def __init__(self,name,speed,hp,atk):
        self.name = name
        self.speed = speed
        self.hp = hp
        self.atk = atk

class Fighter(Plane):                           #Define a Fighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,money):
        Plane.__init__(self,name,speed,hp,atk)  #There self yes Fighter Of self
        self.money= money                       #derived attribute
    def Attack(self,enemyFighter):
        enemyFighter.hp -= self.atk

class EnemyFighter(Plane):                      #Define a EnemyFighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,type):
        Plane.__init__(self,name,speed,hp,atk)  #There self yes EnemyFighter Of self
        self.type = type                        #derived attribute
    def EnemyAttack(self,fighter):
        fighter.hp -= self.atk

f1 = Fighter('player1',150,1000,100,500)
print(f1.__dict__)                              #{'name': 'player1', 'speed': 150, 'hp': 1000, 'atk': 100, 'money': 500}
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
print(Boss1.__dict__)                           #{'name': 'AKS-89', 'speed': 50, 'hp': 3000, 'atk': 500, 'type': 'BOSS'}

Now add a method Attack to the Plane class. When the method of the subclass and the parent class is renamed, when the subclass is called, if there is a name in the subclass, then it must use the subclass. If the subclass does not find the parent class, it will report an error if the parent class does not.

class Plane:                                    #Define a parent class for all fighters
    def __init__(self,name,speed,hp,atk):
        self.name = name
        self.speed = speed
        self.hp = hp
        self.atk = atk
    def Attack(self):
        print(self.name+'Launch bullets!')

class Fighter(Plane):                           #Define a Fighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,money):
        Plane.__init__(self,name,speed,hp,atk)  #There self yes Fighter Of self
        self.money= money                       #derived attribute
    def Attack(self,enemyFighter):
        enemyFighter.hp -= self.atk
        print('Now {0} hp : {1}'.format(enemyFighter.name,enemyFighter.hp))

class EnemyFighter(Plane):                      #Define a EnemyFighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,type):
        Plane.__init__(self,name,speed,hp,atk)  #There self yes EnemyFighter Of self
        self.type = type                        #derived attribute
    def EnemyAttack(self,fighter):
        fighter.hp -= self.atk
        print('Now {0} hp : {1}'.format(fighter.name, fighter.hp))

f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')

f1.Attack(Boss1)                                #Now AKS-89 hp : 2900
Boss1.EnemyAttack(f1)                           #Now player1 hp : 500
Boss1.Attack()                                  #AKS-89 Launch bullets!

Derivative methods: Methods not found in parent classes but specific to subclasses, such as EnemyAttack() above

If a subclass wants to use something of the parent class, it should call the parent class separately.

<1> Parent Class Name. Class Method Name (Self parameter), where the self parameter must be passed

class Fighter(Plane):                           #Define a Fighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,money):
        Plane.__init__(self,name,speed,hp,atk)  #There self yes Fighter Of self
        self.money= money                       #derived attribute
    def Attack(self,enemyFighter):
        Plane.Attack(self)                      #If you want to implement new functions as well as the original functions of the parent class,You also need to call the parent class in the subclass
        enemyFighter.hp -= self.atk
        print('Now {0} hp : {1}'.format(enemyFighter.name,enemyFighter.hp))
f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
f1.Attack(Boss1)                                #player1 Launch bullets!
                                                #Now AKS-89 hp : 2900

< 2 > Super method

class Plane:                                    #Define a parent class for all fighters
    def __init__(self,name,speed,hp,atk):
        self.name = name
        self.speed = speed
        self.hp = hp
        self.atk = atk
    def Attack(self):
        print(self.name+'Launch bullets!')

class Fighter(Plane):                           #Define a Fighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,money):
        super().__init__(name,speed,hp,atk)     #There self yes Fighter Of self
        self.money= money                       #derived attribute
    def Attack(self,enemyFighter):
        Plane.Attack(self)                      #If you want to implement new functions as well as the original functions of the parent class,You also need to call the parent class in the subclass
        enemyFighter.hp -= self.atk
        print('Now {0} hp : {1}'.format(enemyFighter.name,enemyFighter.hp))

class EnemyFighter(Plane):                      #Define a EnemyFighter Class It inherits Plane class
    def __init__(self,name,speed,hp,atk,type):
        super().__init__(name,speed,hp,atk)     #There self yes EnemyFighter Of self
        self.type = type                        #derived attribute
    def EnemyAttack(self,fighter):
        Plane.Attack(self)
        fighter.hp -= self.atk
        print('Now {0} hp : {1}'.format(fighter.name, fighter.hp))

f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
f1.Attack(Boss1)                                #player1 Launch bullets!
                                                #Now AKS-89 hp : 2900
Boss1.EnemyAttack(f1)                           #AKS-89 Launch bullets!
                                                #Now player1 hp : 500

The super() function omits two parameters here, namely the subclass name and the self parameter. super() only exists in new classes and only exists in Python 3, whereas all classes in Python 3 are new classes. For single inheritance, super() can find its parent class; the super() usage above is used inside the class.

Sup () is used outside the class:

f1 = Fighter('player1',150,1000,100,500)
Boss1 = EnemyFighter('AKS-89',50,3000,500,'BOSS')
super(Fighter,f1).Attack()                      #player1 Launch bullets!
super(EnemyFighter,Boss1).Attack()              #AKS-89 Launch bullets!

This function of the parent class can be directly found and invoked.

In single inheritance, a class inherits only one class and in general it can reduce code duplication, improve code readability, and standardize programming patterns.

 

Multiple Inheritance

Multi-inheritance, as its name implies, is a class that inherits two or more parent classes.

<1> Diamond Inheritance:

Assuming that there are four classes, their inheritance relationships are shown in the following figure

class A:
    def fuc(self):
        print('A')
class C(A):
    def fuc(self):
        print('C')
class D(A):
    def fuc(self):
        print('D')
class B(C,D):
    def fuc(self):
        print('B')
b = B()
b.fuc()     #B
First execution of fuc

What is the result of annotating the method of Class B?

class A:
    def fuc(self):
        print('A')
class C(A):
    def fuc(self):
        print('C')
class D(A):
    def fuc(self):
        print('D')
class B(C,D):
    pass
    # def fuc(self):
    #     print('B')
b = B()
b.fuc()     #C
Second implementation of fuc

Re-annotate the method of C class

class A:
    def fuc(self):
        print('A')
class C(A):
    pass
    # def fuc(self):
    #     print('C')
class D(A):
    def fuc(self):
        print('D')
class B(C,D):
    pass
    # def fuc(self):
    #     print('B')
b = B()
b.fuc()     #D
Third implementation of fuc

So the result of the last execution is A.

We can also use B.mro() to know how python goes.

class A:
    def fuc(self):
        print('A')
class C(A):
    def fuc(self):
        print('C')
class D(A):
    def fuc(self):
        print('D')
class B(C,D):
    def fuc(self):
        print('B')
b = B()
print(B.mro())  #[<class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
Result

Why did python look for D first instead of A? Although python actually knew that there was an A behind C when it looked for it, it had to follow the left-to-right direction first and find C->A, D->A. If it found A directly, the node of D would be lost. If a node was lost, it would never be found back, so it should follow the left-to-right direction first and C->A, D->A. The third result is that it prints D.

<2>Tortoise inheritance:

The inheritance relationships of these classes are shown in the following diagram

class A:
    def fuc(self):
        print('A')
class B(A):
    def fuc(self):
        print('B')
class F(A):
    def fuc(self):
        print('F')
class C(B):
    def fuc(self):
        print('C')
class E(F):
    def fuc(self):
        print('E')
class D(E,C):
    def fuc(self):
        print('D')
print(D.mro()) 
#[<class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

This record inheritance order is the inheritance order of the new type class, which follows breadth first.

In Python 2.7, the classical class follows the path of depth first, and it does not go. The result here is D - > E - > F - > A - > C - > B.

Summary:

If one of the parent classes has the same method name, a subclass inherits these parent classes. When it uses this method, it will first look left to right.

Python 2.7 new class coexists with classical class, new class inherits object

Python 3 has only new classes, inheriting object s by default

Another difference between classical and new classes is the existence of mro methods in new classes

 

The Essence of super

Use the diamond inheritance diagram above, but change the code slightly

class A:
    def fuc(self):
        print('A')
class C(A):
    def fuc(self):
        super().fuc()
        print('C')
class D(A):
    def fuc(self):
        super().fuc()
        print('D')
class B(C,D):
    def fuc(self):
        super().fuc()
        print('B')
b = B()
b.fuc()
# A
# D
# C
# B

The essence of super is not simply to find the parent class, but to find it according to the breadth priority of the caller's node location.

Specific implementation process:

Topics: Python Attribute Programming