python|python -继承


目录

  • 继承
    • 继承简介
    • 经典类与新式类
    • 类继承解决了什么问题
    • 多继承的优缺点
      • Mixins机制
    • 继承的查找顺序
    • 多继实现原理
      • 菱形结构
      • 非菱形结构
      • 深度优先和广度优先
        • 深度优先:
        • 广度优先:
    • super()方法
    • 抽象类
    • 方法补充:

继承 python|python -继承
文章图片

继承简介
  1. 继承是一种创建新类的方式,新建的类可称为子类或派生类,父类可称为基类或超类
  2. python支持多继承,新建的类可以支持一个或多个父类
'''单继承和多继承简单定义''' class Parent1: pass class Parent2: pass class Sub1(Parent1): #单继承 pass print(Sub1.__bases__)# 查看自己的父类---->(,)class Sub2(Parent1,Parent2): # 多继承 pass print(Sub2.__bases__)# 查看自己的父类---->(, )

经典类与新式类
【python|python -继承】在py2中有经典类和新式类的区别:
  • 新式类:继承了object类的子类,以及该子类的子类,子子类
  • 经典类:没有继承object类的子类,以及该子类的子类,子子类
'''py2中''' class Foo: pass# 经典类 class Bar(object): pass# 新式类

注意:在py3中没有继承任何类,默认继承object类,所以python3中都是新式类
'''py3中''' class Foo(): pass print(Foo.__bases__) # --->(,),默认继承object类class Sub(Foo): passprint(Sub.__bases__) # ---->(,)

类继承解决了什么问题
  • 类解决对象与对象之间代码冗余的问题,子类可以遗传父类的属性
  • 继承解决的是类与类之间代码冗余的问题
  • object类丰富了代码的功能
示例如下:
'''学生选课系统和老师打分功能''' # 学生类 class Student(): def __init__(self,name,age,gender,course = None): self.name = name self.age = age self.gender = gender self.course = course # 定义一个选课的方法 def choose_course(self,course): if self.course is None: self.course = [] self.course.append(course) print(f"Student choice class --->{self.course}")# 教师类 class Teacher(): def __init__(self,name,age,gender,level): self.name = name self.age = age self.gender = gender self.level = level # 定义一个打分方法 def make_score(self,stu_obj,score): stu_obj.score = score print(f'Teacher{self.name} make {stu_obj.score} to {stu_obj.name}! ')'''有很多冗余的代码,优化一下,定义一个人的类整合一下重复的代码''' # 人类 class Human(): def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender# 学生类 class Student(Human): def __init__(self, name, age, gender, score=None, course=None): Human.__init__(self, name, age, gender) self.score = score self.course = course# 定义一个选课的方法 def choose_course(self, course): if self.course is None: self.course = [] self.course.append(course) print(f"Student choice class --->{self.course}")# 教师类 class Teacher(Human): def __init__(self, name, age, gender, level): Human.__init__(self, name, age, gender) self.level = level# 定义一个打分方法 def make_score(self, stu_obj, score): stu_obj.score = score print(f'Teacher{self.name} make {stu_obj.score}marks to {stu_obj.name}! ')# 学生类实例化 stu = Student('HammerZe', 18, 'male') stu.choose_course('python')# 教师类实例化 teacher = Teacher('li', 18, 'male', 10) teacher.make_score(stu, 90)Student choice class --->['python'] Teacherli make 90marks to HammerZe!

多继承的优缺点
  • 优点:子类可以同时遗传多个父类的属性,最大限度的重用代码
  • 缺点:违反人的思维习惯,一个人有两个爹,代码的可读性会变差,不建议使用多继承,如果不可避免多个父类的继承,应该使用Mixins机制
  • 继承表达的是一种“是”什么关系
Mixins机制
  • 多继承的正确打开方式:mixins机制
  • mixins机制核心:就是在多继承背景下尽可能底提升多继承的可读性
  • 让多继承满足人的思维习惯--->什么“是”什么
class Vehicle: pass class FlyableMixin:# 规范多继承 def fly(self): pass # 民航飞机 class CiviAircraft(FlyableMixin,Vehicle) pass #直升机 class Helicopter(FlyableMixin,Vehicle) pass class Car(Vehicle) pass '''表达是的关系,放在继承的末尾,特们都是交通工具''''''eg:飞机有飞的功能,是交通工具'''

如果有多个功能就必须写多个Mixin类!
继承的查找顺序
  • 对象>子类>父类>父父类
  • 单继承背景下属性查找
示例如下:
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() obj.f2() # 结果 Foo.f2 Bar.f1'''查找顺序: 1.obj先从obj名称空间找,再从Bar名称空间中找,没有f2去他爹(Foo)中找 2.执行Foo中得f2,遇到self.f1()此时self是obj,是Bar的对象 3.执行Bar中的f1 '''# 区别下:父类不想让子类的方法覆盖,可以私有化 class Foo: def __f1(self):# _Foo__f1() print('Foo.f1')def f2(self): # print('Foo.f2') self.__f1()# _Foo__f1()class Bar(Foo): def __f1(self):# # _Bar__f1() print('Bar.f1')obj = Bar() obj.f2()# 结果 Foo.f2 Foo.f1 '''Foo中f1私有化,所以输出的是Foo中的f1'''

多继实现原理 菱形结构
在python中可以继承多个类,这样就会引发下面的结构:
python|python -继承
文章图片

  • 当D继承B和C,B、C分别继承A就会组成一个菱形的继承关系,这样就会涉及到查找属性的顺序问题,A、B、C、中如果方法重名,输出的顺序是按mro列表输出的顺序继承
示例如下:
'''py3中'''class A(): def out_text(self): print('from A')class B(A): def out_text(self): print('from B')class C(A): def out_text(self): print('from C')class D(B,C): passobj = D() obj.out_text() # 结果---->from B ''' 可以打印出mro列表查看顺序''' print(D.mro()) # [, # , # , # , # ]'''这样看来查找顺序就显而易见了, 1、从D中找out_text方法,没有直接去B 2、B中有out_text方法,直接输出停止查找'''

  • mro列表查找准则:
    1. 子类先查,再查父类
    2. 当继承多个父类的时候,按mro列表顺序被检查
    3. 如果继承多个类,被继承类内具有相同的方法,先输出mro列表左边类的方法
  • 注意:mro列表可以写成__mro__也可以,调用mro方法的必须是起始类,obj是D的对象,所以用D.mro()
  • mro列表是通过一个C3线性算法来实现的
非菱形结构
python|python -继承
文章图片

代码实现如下:
'''py3中'''class E: passclass F: passclass B(E): passclass C(F): passclass D: def test(self): print('from D')class A(B, C, D): passprint(A.mro()) ''' 查找顺序如下: [, , , , , , ] '''obj = A() obj.test() # 结果为:from D

深度优先和广度优先
深度优先:
  • 经典类:按深度优先查询
经典类查找顺序如下:
python|python -继承
文章图片

在py2中,没有继承object的类及其子类都是经典类
代码实现:
'''py2中''' class G: def test(self): print('from G') class E(G): def test(self): print('from E') class F(G): def test(self): print('from F') class B(E): def test(self): print('from B') class C(F): def test(self): print('from C') class D(G): def test(self): print('from D')class A(B, C, D): passobj = A() obj.test()# 查找顺序为:obj->A->B->E->G->C->F->D->object# 结果 from B

广度优先:
  • 新式类:按广度优先顺序查找
新式类查找顺序如下:
python|python -继承
文章图片

在py3中,默认为新式类
代码实现如下:
'''py3中''' class G: def test(self): print('from G') class E(G): pass class F(G): pass class B(E): pass class C(F): pass class D(G): def test(self): print('from D')class A(B, C, D): passobj = A() obj.test() # 查找顺序为:obj->A->B->E->C->F->D->G->object# 结果 from D

super()方法
super()方法的存在就是为了解决多重继承的问题,在一个父类中使用super()方法用于调用下一个父类的方法
  • super方法
class A: def test(self): print('from A') super().test() '''用于调用下一个父类的方法B.test'''class B: def test(self): print('from B')class C(A, B): passc = C() c.test() print(C.mro()) # 查找顺序如下 #[, , , ]# 结果 from A from B

抽象类
python的抽象类需要借助模块实现,抽象类是一个特殊的类,它只能被继承,不能被实例化
  • 作用:在不同的模块中通过抽象基类来调用,可以用最精简的方式展示出代码之间的逻辑关系,让模块之间的依赖清晰简单,使得代码的可读性变高。
  • 注意:子类继承抽象类的时候,必须定义相同方法对抽象类的方法进行覆盖
import abc # 抽象类: 抽象类只能被继承,不能被实例化 class Animal(metaclass=abc.ABCMeta):@abc.abstractmethod# 该方法已经是抽象方法了 def speak(self): pass@abc.abstractmethod def login(self):passclass People(Animal): def speak(self): print('嗷嗷嗷')def login(self): passclass Pig(Animal): def speak(self): print('哼哼哼')class Dog(Animal): def speak(self): print('汪汪汪')obj = People() obj.speak()

方法补充:
  1. sel.__class__查看对象所属类
  2. 类名/对象名.__dict__查看类/对象名称空间
  3. 类名/对象名.__bases__查看父类
  4. 起始类名.__mro__打印继承顺序,py3从左到右查找
  5. locals()查看局部名称空间
  6. globals()查看全局名称空间
  7. dirs(str)查看字符串所搭配的内置方法有哪些,查看内容可换
python|python -继承
文章图片

    推荐阅读