# **************************************************************************# Python学习# **************************************************************************# ** 所属主题: 类# ** 所属分层: 05 面向对象三大特性--继承# ** 功能描述: 05 面向对象三大特性--继承# ** 创 建 者: 陈红伟# ** 创建日期: 2021/6/19 5:53 下午# **************************************************************************# ** 修改日期 修改人 修改内容# ** 2021/6/19 陈红伟 新增学习内容代码# **************************************************************************"""本章内容: 继承: 单继承,多继承,__bases__(查看类继承关系) , __dict__(查看对象中的属性), 经典类,新式类,派生(重写),菱形继承,深度优先查找,广度优先查找,mro(),Mixins机制""""""一、什么是继承1、继承是一种创建新类的方式,新建的子类可称之为子类或者派生类,父类又可以称之为基类或超类,子类会遗传父类的属性2、需要注意的是python支持多继承 在python中,新建的类可以继承一个或多个父类"""class Parent1: passclass Parent2: passclass Sub1(Parent1): # 单继承 passclass Sub2(Parent1, Parent2): # 多继承 passprint(Sub1.__bases__) # (<class '__main__.Parent1'>,)print(Sub2.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)"""Ps:在python2中有金典类和新式类之分:新式类:继承了object类的子类,以及该类的子类子子类经典类:没有继承object类的子类,以及该类的子类子子类Ps:在python3中没有继承任何类,那么会默认继承object类,所以python3中所有的类都叫新式类。 所以为了兼容Python2,我们可以在创建类的时候写上继承object(如果没有要求要继承其他类) 例如:class Person(object)"""# 二、python的多继承# 优点:子类可以同事遗传多个父类的属性,最大限度的重用代码# 缺点:# 1、违背人的思维习惯:继承表达的是一种什么是'什么'的关系# 2、代码可读性变差# 3、不建议使用多继承,可扩展性太差# ps:如果真的涉及到一个子类不可避免的要重用多个父类的的属性,应该使用Mixins机制# 三、如何使用继承: 为了解决类与类之间的冗余问题# 示范:class ChwPeople(object): school_name = 'chw' def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sexclass Student(ChwPeople): # school_name = 'chw' # def __init__(self, name, age, sex): # self.name = name # self.age = age # self.sex = sex def choose_course(self): print(f'{self.name}正在选课')stu1 = Student('s1', 16, '男') # 继承之后当前类找不到就会去父类找print(stu1.__dict__) # {'name': 's1', 'age': 16, 'sex': '男'}print(stu1.school_name) # chw# 尖叫提示:如果父类中有定义了属性和方法,子类中也定义,就叫派生 例如Teacher类的school_name和__init__class Teacher(ChwPeople): school_name = 'chw' # 派生 # 派生 def __init__(self, name, age, sex, salary, level): # self.name = name # 因为该类的基类中定义了这三个属性,所以不需要自己定义 # self.age = age # 因为该类的基类中定义了这三个属性,所以不需要自己定义 # self.sex = sex # 因为该类的基类中定义了这三个属性,所以不需要自己定义 # 所以要指名道姓的跟基类要: ChwPeople.__init__(self, name, age, sex) self.salary = salary self.level = level def sorce(self): print(f'{self.name}老师在给学生打分')t1 = Teacher('李老师', 48, '男', 15000, 'A')# print(t1.__dict__)# {'salary': 15000, 'level': 'A'} 【没有加ChwPeople.__init__(self, name, age, sex)这行代码】注释掉后只拿到了两个属性,说明调用的是类Teacher中的init方法print(t1.__dict__)# 【加了ChwPeople.__init__(self, name, age, sex)这行代码】 {'name': '李老师', 'age': 48, 'sex': '男', 'salary': 15000, 'level': 'A'}""" 继承中的菱形继承(死亡钻石) 1、什么是菱形继承: 类:D多继承B和C , B和C都继承A ,A又是一个非object的类。 这种就叫做菱形继承 2、菱形结构带来的问题: 属性查找顺序不一致:【深度优先查找】(一天路走到黑)和【广度优先查找】(最后在找根结点) 【深度优先查找】(金典类用的):沿着一个分支一直找到根结点,在找下一个分支(后面就不会找根结点了,因为已经找过了),直至找到。 【广度优先查找】(新式类用的):沿着一个分支一直找,直到不是根结点,在找下一个分支,直至找到,最后在找根节点。 3、属性查找顺序可以用mro来看: 类名.mro() ps:【python3才有,所以mro是广度查找,因为python都是新式类,都会继承object】 类的mro(): 类以及类的对象访问属性都是参照该类的mro列表,也就是类中属性查找顺序,但是object一定是最后一个找的 总结: 如果多继承是【非菱形继承】,python2和python3中类的属性查找顺序一样,都是一个一个分支找下去,最后在找object 如果多继承是【菱形继承】,python2(中的经典类)和python3(新式类)中类的属性查找顺序不一样,前者是深度优先查找,后者是广度优先查找"""class A: def test(self): print("from A")class B(A): def test(self): print("from B")class C(A): def test(self): print("from C")class D(B, C): passclass E(C, B): pass""" 类的mro(): 类以及类的对象访问属性都是参照该类的mro列表,也就是类中属性查找顺序,但是object一定是最后一个找的"""obj = D()# 类D以及类D的对象访问属性都是参照该类的mro列表print( D.mro()) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, # <class 'object'>]obj.test() # from Bobj = E()print( E.mro()) # [<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]obj.test() # from C""" 继承总结:一、多继承到底又不要用? 要,但是要规避几点问题: 1、继承结构尽量不要过于复杂 2、推荐使用mixins机制:要在多继承的背景下满足继承的什么"是"什么的关系 ==> mixins """"""多继承的正确打开方式:mixins机制 核心:就是在多继承背景下尽可能的提升多继承的可读性 """# 交通工具类class Vehicle(object): def fly(self): pass# 民航飞机类class MinHangFeiJi(Vehicle): pass# 直升飞机类class ZhiShengFeiJi(Vehicle): pass# 汽车类class Car(Vehicle): # 汽车不会非飞,但是按照上述继承关系,他也会飞,所以得新建一个飞行工具的类 passprint("======这是一条华丽的分割线=======")# 交通工具类class Vehicle(object): pass# 飞行工具class FlyableMixin(): # 用Mixin后缀来标识他只是用来记录是属于部分分类的交通工具额外的功能,java中只有单继承,用接口来解决此问题 def fly(self): pass# 爬行工具class paxingMixin(): # 用Mixin后缀来标识他只是用来记录是属于部分分类的交通工具额外的功能,java中只有单继承,用接口来解决此问题 def pa(self): pass# 民航飞机类class MinHangFeiJi(Vehicle, paxingMixin): pass# 直升飞机类class ZhiShengFeiJi(Vehicle, paxingMixin): pass# 汽车类class Car(Vehicle): pass""" 在子类派生的新方法中重用父类的功能: 方式一:指名道姓调用某一个类下的函数 ==> 不依赖于继承关系 方式二:super(),调用父类提供给自己的方法 ==> 严格的依赖继承关系 调用super()会得到一个特殊的对象,该对象会参照当前类的mro,去当前类的父类中找属性 尖叫提示⚠️:super是根据发起属性查找的那个类的mro。去当前类中找属性"""# 方式一、指名道姓调用某一个类下的函数class C1: def __init__(self, name): self.name = name def f1(self): print('C1 f1')class B1(C1): def __init__(self, name, b1, b2): C1.__init__(self, name) # 方式一:指名道姓调用某一个类下的函数 self.b1 = b1 self.b2 = b2b1 = B1('b1', 1, 1)print(b1.__dict__) # {'name': 'b1', 'b1': 1, 'b2': 1}# 方式二、super(),调用父类提供给自己的方法class C1: def __init__(self, name): self.name = name def f1(self): print('C1 f1')class B1(C1): def __init__(self, name, b1, b2): # C1.__init__(self, name) # 方式一:指名道姓调用某一个类下的函数 # super().__init__(name) # python2写法:调用的是方法,自动传入对象 super(B1, self).__init__(name) # python3写法:调用的是方法 self.b1 = b1 self.b2 = b2b1 = B1('b1', 1, 1)print(b1.__dict__) # {'name': 'b1', 'b1': 1, 'b2': 1}# 特别提醒⚠️:# 尖叫提示⚠️:super是根据发起属性查找的那个类的mro。去当前类中找属性class A: def test(self): print('A test')class B: def test(self): print('B test')class C(A,B): passc = C()c.test() # A test # 广度查找class A: def test(self): print('A test') super(A, self).test1()class B: def test(self): print('B test') # def test1(self): # print('B test1')class C(A,B): def test1(self): print("C test1")c = C()print(C.mro()) # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]# c.test() # AttributeError: 'super' object has no attribute 'test1'
总结 以上是内存溢出为你收集整理的Python基础53:面向对象三大特性--继承全部内容,希望文章能够帮你解决Python基础53:面向对象三大特性--继承所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)