全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 数据分析与数据挖掘
789 0
2020-12-17
Python的面向对象编程中的继承-面向所有人的深入指南
继承是面向对象编程(OOP)的最重要方面之一。理解继承的关键是它提供代码的可重用性。一次又一次地代替编写相同的代码,我们可以简单地将一个类的属性继承到另一个类中。
您可以想象,这节省了大量时间。在数据科学中,时间就是金钱!
面向对象编程中的继承
OOP都是关于真实世界的对象的,而继承是表示真实世界关系的一种方式。这是一个例子-汽车,公共汽车,自行车-所有这些都归为更广泛的类别,称为Vehicle。这意味着他们已经继承了类车辆的属性,即全部用于运输。
我们可以借助继承在代码中表示这种关系。
关于继承的另一个有趣的事情是它本质上是可传递的。但是,这是什么意思?我们将在本文后面详细介绍。Python还支持各种类型的继承,我将在本文中详细介绍。
这是与面向对象编程相关的系列文章中的第二篇。请同时阅读第一篇文章:
面向对象编程的基本概念。
目录
什么是面向对象编程中的继承?
面向对象编程中不同形式的继承
单继承
多重继承
多层次继承
层次继承
混合继承
方法覆盖
super()函数
什么是面向对象编程中的继承?
继承是一个类继承另一个类的属性和方法的过程。继承其属性和方法的类称为Parent类。从父类继承属性的类是Child类。
有趣的是,连同继承的属性和方法,子类可以具有自己的属性和方法。
您可以使用以下语法:\在Python中实现继承:
class parent_class:
父类的主体
class child_class(parent_class):
儿童班的身体
让我们看一下实现:
车级:#父级
    def __init __(个人,姓名,里程):
        self.name =名称
        self.mileage =里程
    def描述(自己):               
        return f“ {self.name}汽车的行驶里程为{self.mileage} km / l”
宝马(汽车)级:#儿童级
    通过
奥迪(汽车)类别:#child类别
    def audi_desc():
        返回“这是奥迪类的描述方法。”
obj1 = BMW(“ BMW 7-series”,39.53)
打印(obj1.description())
obj2 = Audi(“ Audi A8 L”,14)
打印(obj2.description())
打印(obj2.audi_desc())
输出:
面向对象编程中的继承
我们创建了两个子类“ BMW”和“ Audi”,它们继承了父类“ Car”的方法和属性。在BMW类中,我们没有提供其他功能和方法。而Audi类中还有另外一种方法。
注意子类的对象如何在obj1.description()和obj2.description()的帮助下访问父类的实例方法description()。而且,也可以使用obj2.audi_desc()访问Audi类的单独方法。
我们可以使用内置的类属性__bases__检查任何类的基类或父类。
打印(宝马.__ bases__,奥迪.__ bases__)
面向对象编程中的继承-打印类
就像我们在这里可以看到的那样,两个子类的基类都是Car。现在,让我们看看将__base__与父类Car一起使用会发生什么:
打印(Car .__ bases__)
面向对象编程中的继承-打印子类
每当我们在Python 3.x中创建新类时,它都会从称为Object的内置基本类继承。换句话说,Object类是所有类的根。
面向对象编程中的继承形式
根据父级和子级的参与,可以广泛地继承五种形式。
1.单一继承
这是一种继承形式,其中一类仅继承一个父类。这是继承的简单形式,因此也称为简单继承。
家长:
  def f1(self):
    print(“父类的功能。”)
子类(父母):
  def f2(自我):
    print(“子类的功能。”)
object1 = Child()
object1.f1()
object1.f2()
面向对象编程中的继承-单一继承
在这里,Child类仅继承一个Parent类,因此这是Single继承的一个示例。
2.多重继承
当一个类继承多个父类时,一个继承成为多个继承。从各个父类继承属性的子类可以访问其所有对象。
类别Parent_1:
  def f1(self):
    print(“ parent_1类的功能。”)
父类_2:
  def f2(自我):
    print(“ parent_2类的功能。”)
Parent_3类:
  def f3(self):
    print(“ parent_3类的功能。”)
子类别(Parent_1,Parent_2,Parent_3):
  def f4(self):
    print(“子类的功能。”)
object_1 = Child()
object_1.f1()
object_1.f2()
object_1.f3()
object_1.f4()
面向对象编程中的继承-多重继承
在这里,我们有一个Child类,它继承了三父类Parent_1,Parent_2和Parent_3的属性。所有类具有不同的功能,并且所有功能均使用Child类的对象来调用。
但是,假设一个子类继承了两个具有相同功能的类:
类别Parent_1:
  def f1(self):
    print(“ parent_1类的功能。”)
父类_2:
  def f1(self):
    print(“ parent_2类的功能。”)
班级Child(Parent_1,Parent_2):
  def f2(自我):
    print(“子类的功能。”)
在这里,类Parent_1和Parent_2具有相同的函数f1()。现在,当Child类的对象调用f1()时,由于Child类继承了两个父类,因此您认为应该怎么办?
obj = Child()
obj.f1()
面向对象编程中的继承
但是,为什么不继承Parent_2类的函数f1()?
在多重继承中,子类首先在其自己的类中搜索方法。如果未找到,则以父类depth_first和左右顺序搜索。因为这是一个只有两个父类的简单示例,所以我们可以清楚地看到Parent_1类是首先继承的,因此子类将在Parent_1类中搜索该方法,然后再在Parent_2类中进行搜索。
但是对于复杂的继承问题,很难确定顺序。因此,执行此操作的实际方法称为Python中的方法解析顺序(MRO)。我们可以使用__mro__属性找到任何类的MRO
孩子.__ mro__
面向对象编程中的继承-MRO
这表明Child类首先访问了Parent_1类,然后访问了Parent_2,因此将调用Parent_1的f1()方法。
让我们在Python中举一个复杂的例子:
类别Parent_1:
通过
父类_2:
通过
Parent_3类:
通过
类别Child_1(Parent_1,Parent_2):
通过
子类别Child_2(Parent_2,Parent_3):
通过
类别Child_3(Child_1,Child_2,Parent_3):
通过
在这里,类Child_1继承了两个类– Parent_1和Parent_2。Child_2类还继承了两个类– Parent_2和Parent_3。另一个类Child_3继承了三个类– Child_1,Child_2和Parent_3。
现在,仅通过查看此继承,就很难为类Child_3确定方法解析顺序。这是__mro __-的实际用法
Child_3 .__ mro__
我们可以看到,解释器首先搜索Child_3,然后搜索Child_1,然后分别搜索Parent_1,Child_2,Parent_2和Parent_3。
3.多层次继承
例如,class_1被class_2继承,而class_2也被class_3继承,此过程继续进行。这称为多级继承。让我们看一个例子:
家长:
  def f1(self):
    print(“父类的功能。”)
班级Child_1(父母):
  def f2(自我):
    print(“ child_1类的功能。”)
类别Child_2(Child_1):
  def f3(self):
    print(“ child_2类的功能。”)
obj_1 = Child_1()
obj_2 = Child_2()
obj_1.f1()
obj_1.f2()
打印(“ \ n”)
obj_2.f1()
obj_2.f2()
obj_2.f3()
在这里,类Child_1继承了Parent类,而类Child_2继承了Child_1类。在此Child_1可以访问函数f1()和f2(),而Child_2可以访问函数f1(),f2()和f3()。如果我们尝试使用类Class_1的对象访问函数f3(),则将发生错误,指出:
“ Child_1”对象没有属性“ f3”
obj_1.f3()
4-层次继承
在这种情况下,各种子类都继承一个父类。继承简介中给出的示例是分层继承的示例,因为BMW类和Audi类继承了Car类。
为了简单起见,让我们看另一个示例:
家长:
deff1(自己):
print(“父类的功能。”)
班级Child_1(父母):
deff2(自己):
print(“ child_1类的功能。”)
子类别Child_2(Parent):
deff3(自己):
print(“ child_2类的功能。”)
obj_1 = Child_1()
obj_2 = Child_2()
obj_1.f1()
obj_1.f2()
打印('\ n')
obj_2.f1()
obj_2.f3()
在这里,两个子类继承了同一个父类。类Child_1可以访问Parent类的函数f1()和其自身的函数f2()。而Child_2类可以访问Parent类的函数f1()和其自身的函数f3()。
5-混合继承
当存在多种形式的继承组合时,称为混合继承。此示例后将更加清楚:
家长:
  def f1(self):
    print(“父类的功能。”)
班级Child_1(父母):
  def f2(自我):
    print(“ child_1类的功能。”)
子类别Child_2(Parent):
  def f3(self):
    print(“ child_2类的功能。”)
类别Child_3(Child_1,Child_2):
  def f4(self):
    print(“ child_3类的功能。”)
obj = Child_3()
obj.f1()
obj.f2()
obj.f3()
obj.f4()
在此示例中,两个类'Child_1'和'Child_2'是使用分层继承从基类'Parent'派生的。另一个类'Child_3'是使用多个继承从类'Child_1'和'Child_2'派生的。现在使用混合继承派生了“ Child_3”类。
方法覆盖
覆盖的概念在继承中非常重要。它赋予子类/子类特殊的功能,以为其子类中已经存在的方法提供特定的实现。
家长:
  def f1(self):
    print(“父类的功能。”)
子类(父母):
  def f1(self):
    print(“ Child类的功能。”)
obj = Child()
obj.f1()
此处,Child类的函数f1()覆盖了Parent类的函数f1()。每当Child类的对象将调用f1()时,Child类的功能就会被执行。但是,父类的对象可以调用父类的函数f1()。
obj_2 = Parent()
obj_2.f1()
super()函数
Python中的super()函数返回一个使用super关键字引用父类的代理对象。这个super()关键字基本上在访问父类的重写方法时很有用。
super()函数的正式文档提供了super()的两个主要用途:
在具有单一继承的类层次结构中,super可以在不显式命名父类的情况下引用父类,从而使代码更具可维护性。
例如-
家长:
  def f1(self):
    print(“父类的功能。”)
子类(父母):
  def f1(self):
    super()。f1()
    print(“ Child类的功能。”)
obj = Child()
obj.f1()
在这里,借助于super()。f1(),已调用Child类(即Parent类)的超类的f1()方法,而未对其进行明确命名。
这里要注意的一件事是super()类可以接受两个参数-第一个是子类的名称,第二个是作为该子类的实例的对象。让我们看看如何-
家长:
  def f1(self):
    print(“父类的功能。”)
子类(父母):
  def f1(self):
    超级(孩子,自我).f1()
    print(“ Child类的功能。”)
obj = Child()
obj.f1()
第一个参数引用子类Child,而第二个参数引用Child的对象,在这种情况下,该对象是self。您可以在使用super()和super(Child,self)之后看到输出相同,因为在Python 3中,super(Child,self)等同于self()。
现在,让我们看看使用__init__函数的另一个示例。
父类(对象):
  def__init __(self,ParentName):
    print(ParentName,'从另一个类派生。')
子类(父母):
  def__init __(self,ChildName):
    打印(名称,是一个子类。)
    super().__ init __(ChildName)
obj = Child('Child')
我们在这里所做的是我们使用super().__ init __(ChildName)调用了Parent类(在Child类内部)的__init__函数。而且,由于Parent类的__init__方法需要一个参数,因此已将其作为“ ChildName”传递。因此,在创建Child类的对象之后,首先执行Child类的__init__函数,然后执行Parent类的__init__函数。
第二个用例是在动态执行环境中支持协作式多重继承。
First()类:
  def __init __():
    打印(“第一”)
    super().__ init __()
Second()类:
  def __init __():
    打印(“第二”)
    super().__ init __()
第三类(第二,第一):
  def __init __():
    打印(“第三”)
    super().__ init __()
obj = Third()
super()调用在每个步骤中都会在MRO中找到下一个方法,这就是为什么First和Second也必须拥有它的原因,否则,执行将在first().__ init__的末尾停止。
请注意,First和Second的超类都是Object。
让我们找到Third()的MRO
第三.__ mro__
顺序是“第三”>“第二”>“第一”,输出的顺序也相同。
题库
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群