day 20

1. 类的继承

1.1 什么是继承

  • 继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类
  • 继承的特性是:子类会遗传父类的属性,而且能够派生出本身的属性
  • 继承是类与类之间的关系

在 python 中,一个子类能够继承多个父类,其余语言只能一个子类继承一个父类。编程

1.2 为何要有继承

目的:减小代码冗余(减小重复代码)编程语言

1.3 如何实现继承

  1. 先肯定谁是子类,谁是父类函数

  2. 在定义类时,子类 + (),括号内填父类的名字,实现继承设计

    使用 __bases__ 方法,能够获取当前类所继承的类3d

    class Father1:
        pass
    
    
    class Father2:
        pass
    
    
    class Son1(Father1):
        pass
    
    
    class Son2(Father1, Father2):
        pass
    
    
    print(Son1.__bases__) # 查看父类
    
    print(Son2.__bases__)

    运行结果:code

    (<class '__main__.Father1'>,)
    (<class '__main__.Father1'>, <class '__main__.Father2'>)
    
    Process finished with exit code 0

1.4 类与抽象

  • 继承的关系
    • 对象是特征与技能的结合体
    • 类是一系列对象相同的特征与技能的结合体
    • 继承是一系列类相同的特征与技能的结合体

继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承,抽象即抽取相似或者说比较像的部分。对象

抽象分红两个层次:blog

  1. 将奥巴马和梅西这俩对象比较像的部分抽取成类;
  2. 将人,猪,狗这三个类比较像的部分抽取成父类。

抽象最主要的做用是划分类别(能够隔离关注点,下降复杂度),以下图所示:继承

继承:基于抽象的结果,经过编程语言去实现它,确定是先经历抽象这个过程,才能经过继承的方式去表达出抽象的结构。

抽象只是分析和设计的过程当中,一个动做或者说一种技巧,经过抽象能够获得类,以下图所示:

1.5 查找顺序

在继承背景下,对象属性的查找顺序:

  1. 对象查找属性会先从对象的名称空间中查找
  2. 若对象没有,则会去类里面找
  3. 若当前类是子类,而且没有对象找的属性,会去父类中查找

注意:对象查找属性,若子类有,无论父类有没有,以子类的为准。

class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1()


class Bar(Foo):
    def f1(self):
        print('Bar.f1')


# 对象查找属性的顺序:对象本身-》对象的类-》父类-》父类。。。
obj = Bar()  # self是obj自己,即找到Bar的f1()
obj.f2()

运行结果:

Foo.f2
Bar.f1

Process finished with exit code 0

2. 派生

2.1 什么是派生

子类中新定义的属性的这个过程叫作派生,而且须要记住子类在使用派生的属性时始终以本身的为准。

2.2 派生方法

2.2.1 类调用

指名道姓访问某一个类的函数:该方式与继承无关

# 直接经过 父类.(调用)__init__,把__init__当作普通函数使用,传入对象与继承的属性.
class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Son(Father):
    def __init__(self, name, age, weight, height):
        Father.__init__(self, name, age)
        self.weight = weight
        self.height = height

2.2.2 super() 方法

  • 严格依赖继承属性查找关系
  • super() 会获得一个特殊的对象,该对象就是专门用来访问父类中的属性的(按照继承的关系)
  • super().__init__ (不用为self传值)
  • super() 的完整用法是 super(本身的类名,self) ,在python2中须要写完整,而python3中能够简写为 super()
class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Son(Father):
    def __init__(self, name, age, weight, height):
        super().__init__(name, age)
        self.weight = weight
        self.height = height

3. 类的分类(了解)

在 python2 中,才有才会有新式类与经典类之分;在 python3 中,全部的类都是新式类。

3.1 新式类

继承 object 的类都称之为新式类。

在 python3 中,若是子类没有继承自定义的类,都默认继承 object 。

class Foo():
    pass


class Goo(Foo):
    pass


print(Foo.__bases__) 
print(Goo.__bases__)

运行结果:

(<class 'object'>,) # 默认继承 object
(<class '__main__.Foo'>,)

Process finished with exit code 0

3.2 经典类

在 python2 中,凡是没有继承 object 的类都是经典类。

4. 菱形继承问题

4.1 菱形继承问题

在Java和C#中子类只能继承一个父类,而Python中子类能够同时继承多个父类,如A(B,C,D)

若是继承关系为非菱形结构,则会按照先找B这一条分支,而后再找C这一条分支,最后找D这一条分支的顺序直到找到咱们想要的属性

若是继承关系为菱形结构,即子类的父类最后继承了同一个类,那么属性的查找方式有两种:

  • 经典类下:深度优先
  • 广度优先:广度优先

经典类:一条路走到黑,深度优先

新式类:不找多各种最后继承的同一个类,直接去找下一个父类,广度优先

可使用下面的代码逐一进行验证:

# 验证
class A:
    def test(self):
        print('from A')

    pass


class B(A):
    def test(self):
        print('from B')

    pass


class C(A):
    def test(self):
        print('from C')

    pass


class D(B):
    def test(self):
        print('from D')

    pass


class E(C):
    def test(self):
        print('from E')

    pass


class F(D, E):
    def test(self):
        print('from F')

    pass


f1 = F()
f1.test()

结果:

# 新式类: F-D-B-E-C-A-object
# 经典类: F-D-B-A-E-C

4.2 mro() 方法

对于多继承的类,python 提供了 mro() 方法,便捷的查看继承的查找顺序。

对于上述代码,咱们可使用 mro() 方法:

# print(F.mro())
# 新式类下:
for i in F.mro():
    print(i)

运行结果:

<class '__main__.F'>
<class '__main__.D'>
<class '__main__.B'>
<class '__main__.E'>
<class '__main__.C'>
<class '__main__.A'>
<class 'object'>

Process finished with exit code 0
相关文章
相关标签/搜索