面向对象之继承

  • 继承定义
  • 继承语法深入
  • 子类重用父类方式
  • 属性查找
  • 属性查找顺序
  • 继承的实现原理
  • **下图为非菱形查找顺序:**
  • 下图是经典类菱形时的查找顺序:
  • 下图是新式类菱形时的查找顺序:
  • 通过函数mro()拿到调用顺序
  • Mixins机制


继承定义

1 什么是继承
继承是一种新建类的方式,新建的类称之为子类,被继承的类称之为
父类、基类、超类

  • python支持多继承

2 为何要继承
子类会遗传父类的属性,所以继承是用来解决类与类之间代码冗余问题

3、如何实现继承
语法:

class Parent1:
    pass

class Parent2:
    pass

class Sub1(Parent1):
    pass

class Sub2(Parent1,Parent2):
    pass

继承语法深入

子类重用父类方式

在子类派生的新方法中重用父类的功能
方式一:指名道姓地调用某一个类的函数

  • 特点:不依赖于继承关系

定义处语法:

class OldboyPeople:
    school = "oldboy"
    #             空对象,"艾利克斯",73,'male'
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(OldboyPeople):
    #            空对象,"艾利克斯",73,'male',1001,"python全栈开放"
    def __init__(self,name,age,gender,stu_id,course):
        OldboyPeople.__init__(self,name,age,gender)  # OldboyPeople.__init__(空对象,"艾利克斯",73,'male')
        self.stu_id = stu_id
        self.course = course

属性查找

错误示例:

class Foo:
    def f2(self):
        print("Foo.f2")

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


class Bar(Foo):
    def f2(self):
        print("Bar.f2")

obj = Bar()
obj.f1()  # Foo.f1  Bar.f2

这个错误示例展示了子类方法覆盖了父类方法,使父类的f2没有调用

正确示例方法一:
父类如果不想让子类覆盖自己的方法,可以在方法名前加前缀__

class Foo:
    def __f2(self):  # _Foo__f2
        print("Foo.f2")

    def f1(self):
        print('Foo.f1')
        self.__f2()  # obj._Foo__f2()

class Bar(Foo):
    def __f2(self):  # _Bar__f2
        print("Bar.f2")

obj = Bar()
obj.f1()

属性查找顺序

补充知识:

  • 新式类:但凡是继承了object类的子类,以该子类子子孙孙类都称之为新式类
  • 经典类:没有继承了object类的子类,以该子类子子孙孙类都称之为经典类

python3中全都是新式类,python2中才有经典类:
在python3中没有继承任何类的类会默认继承object类

继承的实现原理

菱形问题:一个子类继承的多条件分支最终汇聚到一个非object类,在菱形继承下
新式类与经典类关于属性查找的方式不同

新式类:广度优先
经典类:深度优先

下图为非菱形查找顺序:

python 虚拟继承 python继承机制_子类

下图是经典类菱形时的查找顺序:

按A括号内继承的顺序从左往右,一个一个往上查找,第一个会查找到最顶级,之后的查找时忽略顶级

python 虚拟继承 python继承机制_子类_02

下图是新式类菱形时的查找顺序:

按A括号内继承的顺序从左往右,一个一个往上查找,最后一个会查找到最顶级,之前的查找时忽略顶级

python 虚拟继承 python继承机制_python 虚拟继承_03

通过函数mro()拿到调用顺序

print(A.mro())

Mixins机制

Python语言可没有接口功能,但Python提供了Mixins机制,简单来说Mixins机制指的是子类混合(mixin)不同类的功能,而这些类采用统一的命名规范(例如Mixin后缀),以此标识这些类只是用来混合功能的,并不是用来标识子类的从属"is-a"关系的,所以Mixins机制本质仍是多继承,但同样遵守”is-a”关系。
使用Mixin类实现多重继承要非常小心

  • 首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀
  • 其次它必须责任单一,如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类
  • 然后,它不依赖于子类的实现
  • 最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)

Mixins是从多个类中重用代码的好方法,但是需要付出相应的代价,我们定义的Minx类越多,子类的代码可读性就会越差,并且更恶心的是,在继承的层级变多时,代码阅读者在定位某一个方法到底在何处调用时会晕头转向