Python继承


2021年8月23日, Learn eTutorial
3213

在本教程中,您将掌握面向对象编程的基本概念,如继承、封装等,包括它们的语法和示例。此外,您还将了解OOP中不同类型的继承。

面向对象编程方法是最重要且被普遍接受的编程方法,因为它完全依赖于对象和类,这鼓励了模块化和软件可重用性。

面向对象编程的四个基本构建块是

  1. 继承
  2. 封装
  3. 多态
  4. 抽象
building blocks of object oriented programming

面向对象编程的四个基本构建块

本教程将详细介绍每种方法。所以,让我们开始学习继承。

什么是继承

继承可以定义为一个类在不修改现有类的情况下获取现有类特征(属性和方法)的过程。继承特征的类称为子类或派生类,从中继承特征的类称为父类或基类。换句话说,新形成的类是子类,而现有类称为父类。

例如,在现实世界中,父亲和母亲代表父类,而他们的孩子代表子类。孩子从父母那里获得了许多特征,同时,孩子也拥有父母可能没有的独特特征。用编程术语来说,我们可以说子类继承了父类的所有属性和方法,但同时子类也拥有自己独特的特性。

继承的语法如下

class Parent_class:
    Body of parent_class
class Child_class(Parent_class):
    Body of Child_class
 

Python中不同类型的继承

在Python中,继承分为五种类型。它们是:

  • 单继承
  • 多级继承
  • 层次继承
  • 多重继承
  • 混合继承
Hierarchical structure of the package

Python继承类型

Python中的单继承

单继承是最简单、最容易的继承类型之一。在单继承中,子类继承父类的所有属性和方法。这使得代码可重用和模块化。

Hierarchical structure of the package

单继承

在这种情况下,A类是父类,B类是子类。B类有其自己独特的属性和方法,但仍然继承了A类的属性和方法。

单继承的语法如下:

class A:
    pass
class B(A):
    pass 

观察此示例以查找矩形的面积。这里,Shape是父类,Rect是子类。在父类中,我们有一个函数display(),用于显示矩形的长度和宽度。在子类中,我们定义了函数area()来计算矩形的面积并打印输出。

class Shape: #Parent Class

    def __init__(self,name,length,breadth):
        self.name=name
        self.l=length
        self.b=breadth

    def display(self):
        print("Length is :",self.l)
        print("Breadth is :",self.b)

class Rect(Shape): #Child Class

    def area(self):
        a=self.l*self.b
        print("Area of",self.name,"is",a)

ob = Rect('Rectangle',10,20)
ob.display()
ob.area() 

输出:

Length is : 10
Breadth is : 20
Area of Rectangle is 200

观察示例,您会注意到以下几点:

  • ob = Rect('Rectangle',10,20) 表示已创建子类实例。
  • ob.display():显示子类继承了父类中的函数。display()函数是父类Shape中的一个方法。
  • ob.area():表明子类Rect调用了其自身中的函数。

Python中的多级继承

多级继承是一种继承类型,其中从派生类创建的类本身继承了一个基类。多级继承显示了从派生类或子类继承的可能性。因此,最简单的多级继承是三层结构,其中子类从派生类继承特性,而派生类又从超类继承属性。

Multilevel Inheritance

多级继承

在这里,A类是超类,B类是派生类,C类是子类。C类可以继承B类和A类的所有属性,而B类只能继承A类的特性。

语法如下 :

class A:
    pass
class B(A):
    pass
class C(B):
    pass 

让我们看看我们之前的示例是如何改变的。在这里,我们创建了一个名为Square的新类,它是Rect类的子类。


class Shape: #Superclass

    def __init__(self,name,length,breadth):
        self.name=name
        self.l=length
        self.b=breadth

    def display(self):
        print("Length is :",self.l)
        print("Breadth is :",self.b)

class Rect(Shape): #Derived Class

    def area(self):
      
        a=self.l*self.b
        print("Area of",self.name,"is",a)

class Square(Rect): #Child Class

    def peri(self):
        p =4*self.l 
        print("Perimeter of",self.name,"is",p)

obs = Square('Square',20,20)
obs.display()
obs.area()
obs.peri() 

输出

Length is : 20
Breadth is : 20
Area of Square is 400
Perimeter of Square is 80

从示例中,您会注意到以下几点:

  • obs是Square类(子类)的实例。
  • obs.display()表示子类Square调用了父类Shape中的display()函数。
  • obs.area()表示类Square继承了派生类Rect中的area()函数。
  • obs.peri()表示peri()函数是Square类中的一个方法。

注意:子类可以访问超类,但反之则不然。

Python中的层次继承

层次继承是一种继承类型,其中从基类创建了多个子类。

Hierarchical Inheritance in Python

Python中的层次继承

上图说明了层次结构,其中B类和C类继承了A类的属性,尽管它们都有自己独特的特性。

语法如下 :

class A:
    pass
class B(A):
    pass
class C(A):
    pass 

现在,让我们更改Shape类并看看层次继承是如何工作的。在这种情况下,我们有一个名为Shape的基类和两个子类,即RectTri。两个类都从Shape类继承display()函数来打印长度和宽度。在Rect类中,我们计算矩形的面积;而在Tri类中,我们使用两个不同的函数R_area()T_area()来计算三角形的面积。

class Shape:

    def __init__(self,name,length,breadth):
        self.name=name
        self.l=length
        self.b=breadth

    def display(self):
        print("Length is :",self.l)
        print("Breadth is :",self.b)

class Rect(Shape):
    def R_area(self):
        a=self.l*self.b
        print("Area of",self.name,"is",a)

class Tri(Shape):
    def T_area(self):
        a=0.5*self.l*self.b
        print("Area of",self.name,"is",a)

obr = Rect('Rectangle',10,20)
obr.display()
obr.R_area()

obt = Tri('Triangle',10,20)
obt.display()
obt.T_area() 

输出

Length is : 10
Breadth is : 20
Area of Rectangle is 200

Length is : 10
Breadth is : 20
Area of Triangle is 100.0

这里,由于我们使用了两个独立的子类,因此需要创建两个对象。obrRect类的对象,obtTri类的对象。使用obr,我们调用了base类Shape的特性函数display()。同样,对象obt调用函数display()。因此,这里两个不同的对象继承了它们基类的相同特性。除此之外,通过对象,两个类都调用了它们各自类Rect和Tri中定义的函数R_area()T_area()

Python中的多重继承

当一个子类从两个基类创建时,它被称为多重继承。顾名思义,派生类继承了两个不同类的特性。

Multiple Inheritance in Python

Python中的多重继承

图示了C类对A类和B类属性的继承。在这里,A类和B类是C类的基类,C类可以获取这两个类的属性和方法。在现实生活中,孩子会继承父母双方的特征。

语法如下 :

class A:
    pass
class B:
    pass
class C(A , B):
    pass 

不使用super的多重继承

下面的示例展示了在Python中不使用super()的多重继承的工作方式。在这个例子中,我们有两个基类,即Mom类和Dad类,我们的子类是Kid。Kid类可以使用其对象obk从Mom类和Dad类继承特性,如示例所示。每个类都有独立的定义为feature_mfeature_dfeature_k的方法。

class Mom:
    def feature_m(self):
        print("Iam your mom")

class Dad:
    def feature_d(self):
        print("Iam your dad")

class Kid(Mom,Dad):

    def feature_k(self):
        print("Iam the Kid")

obk = Kid()
obk.feature_m()
obk.feature_d()
obk.feature_k() 

输出

Iam your mom
Iam your dad
Iam the Kid

使用super()的多重继承

多重继承赋予了子类继承任意多个基类的自由。因此,在使用多重继承时,如果多个基类使用相同的名称来定义方法,会发生什么?让我们通过示例来理解。

class Mom:
    def feature(self):
        print("Iam your mom")

class Dad:
    def feature(self):
        print("Iam your dad")

class Kid(Mom,Dad):

    def feature(self):
        print("Iam the Kid")

obk = Kid()
obk.feature() 

输出

Iam the Kid

这里我们对之前的示例做了一些小改动。所有方法都有相同的名称。我们收到的输出是“I am the kid”,它定义在子类Kid的feature方法中。为什么会这样?这是因为这里创建的是子类的对象,它总是首先调用自己的方法。

那么,我们应该如何访问其父类的特性呢?Python提供了一个名为super的关键字来解决这个问题。下面的程序将对此进行说明。

class Mom:
    def feature(self):
        print("I am your mom")

class Dad:
    def feature(self):
        print("I am your dad")

class Kid(Mom,Dad):

    def feature(self):
        super().feature()
        print("I am the Kid")

obk = Kid()
obk.feature()

输出


I am your mom
I am the Kid

程序中的一个小改动会带来新的结果。super().feature()调用了超类Mom中的方法。您是否想过它为什么没有调用它另一个超类Dad中的方法?接下来的部分将为您提供恰当的答案。

什么是方法解析顺序

方法解析顺序(Method Resolution Order),在Python中通常称为MRO,是一套规则,用于搜索Python在类层次结构中查找方法的顺序。派生类被调用的顺序。方法被调用的顺序称为线性化

MRO在处理多级继承场景时起着至关重要的作用,尤其是在处理多重继承时。原因在于,当层次结构中的多个类具有相同的方法时,Python首先在当前类中搜索给定的方法或属性,如果找不到,则以深度优先、从左到右的顺序搜索其父类。层次结构中的每个类都被搜索一次,直到到达其最终的基类,即object类。这意味着在Python中,任何用户定义类或内置类的基类都是object类。您将在下面的示例中清楚地了解。

Python提供了两种查看类MRO的方法:

  1. 使用mro()方法,该方法返回一个列表。
  2. 使用MRO属性(_mro_),该属性返回一个元组。
class Mom:
    def feature(self):
        print("I am your mom")

class Dad:
    def feature(self):
        print("I am your dad")

class Kid(Mom,Dad):

    def feature(self):
        super().feature()
        print("I am the Kid")

obk = Kid()
obk.feature()

print(Kid.mro())  
print(Kid.__mro__)

输出

I am your mom
I am the Kid


[<class '__main__.Kid'>, <class '__main__.Mom'>, <class '__main__.Dad'>, <class 'object'>]

(<class '__main__.Kid'>, <class '__main__.Mom'>, <class '__main__.Dad'>, <class 'object'>)

对于Kid类,MRO顺序是Kid ----> Mom ----> Dad ----> object class

注意:MRO始终确保子类出现在其父类之前。

Python中的混合继承

混合继承是Python中的一种继承,它结合了一种或多种继承形式,例如,多级继承与多重继承相结合。因此,它可以在超类和子类之间包含任意数量的中间类。随着层级的提高,复杂性也随之增加。

Hybrid Inheritance in Python

Python中的混合继承

在这里,我们的混合结构中,D类是由两个派生类B和C创建的,它们的基类是A。这表明了多级继承和多重继承的结合。

观察下面的示例。

class Shape:
    def __init__(self,name,length,breadth):
        self.name=name
        self.l=length
        self.b=breadth

    def display(self):
        print("Length is :",self.l)
        print("Breadth is :",self.b)

class Rect(Shape):
    def R_area(self):
        a=self.l*self.b
        print("Area of",self.name,"is",a)

class Square(Shape):
    def peri(self):
        p =4*self.l 
        print("Perimeter of square is",p)

class Quad(Rect, Square):
     def prt(self):
        print('Rectangle and Square are quadrilaterals')
obq = Quad('Rectangle',10,20)
obq.display()
obq.R_area()
obq.peri()
obq.prt()
print(Quad.mro()) 

输出


Length is : 10
Breadth is : 20
Area of Rectangle is 200
Perimeter of square is 40
Rectangle and Square are quadrilaterals
[<class '__main__.Quad'>, <class '__main__.Rect'>, <class '__main__.Square'>, <class '__main__.Shape'>, <class 'object'>]

类quad的MRO顺序是Quad ----> Rect ----> Square ----> Shape ----> Object。

Python内置继承方法

Python提供了两种内置的继承方法来检查继承方法。它们是:

  1. isinstance():如果给定的对象是类或类型,则返回true,否则返回false。语法如下:
    isinstance( object, type) 
    
  2. issubclass():如果给定的对象是某个类的子类,则返回true,否则返回false。
    issubclass( object, class) 
    

对于我们之前的例子,让我们看看内置方法是如何在Python中检查继承的。

x = isinstance(obq, Quad)
print(x)

x = issubclass(Rect,Shape)
print(x) 

输出

True
True