python 继承(史上最详细版本)

目录

继承

继承简介

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

class Sub2(Parent1,Parent2): # 多继承
    pass
print(Sub2.__bases__)    # 查看自己的父类---->(<class '__main__.Parent1'>, <class '__main__.Parent2'>)

经典类与新式类

python学习资源汇总 需要的伙伴自取腾讯文档-在线PDFhttps://docs.qq.com/pdf/DR1doYmNBYUZ3RVNX

在py2中有经典类和新式类的区别:

  • 新式类:继承了object类的子类,以及该子类的子类,子子类

  • 经典类:没有继承object类的子类,以及该子类的子类,子子类

  • '''py2中'''
    class Foo:
        pass     # 经典类
    class Bar(object):
        pass     # 新式类

    注意:在py3中没有继承任何类,默认继承object类,所以python3中都是新式类

    '''py3中'''
    class Foo():
        pass
    print(Foo.__bases__) # --->(<class 'object'>,),默认继承object类
    
    class Sub(Foo):
        pass
    
    print(Sub.__bases__) # ---->(<class '__main__.Foo'>,)

    类继承解决了什么问题

  • 类解决对象与对象之间代码冗余的问题,子类可以遗传父类的属性
  • 继承解决的是类与类之间代码冗余的问题
  • 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机制 参考

  • 继承表达的是一种“是”什么关系

  • 继承的查找顺序

  • 对象>子类>父类>父父类

  • 单继承背景下属性查找

  • 示例如下:

    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中可以继承多个类,这样就会引发下面的结构:

  • 当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):
        pass
    
    obj = D()
    obj.out_text() # 结果---->from B
    ''' 可以打印出mro列表查看顺序'''
    print(D.mro())
    # [<class '__main__.D'>,
    # <class '__main__.B'>, 
    # <class '__main__.C'>, 
    # <class '__main__.A'>,
    # <class 'object'>]
    
    '''这样看来查找顺序就显而易见了,
    1、从D中找out_text方法,没有直接去B
    2、B中有out_text方法,直接输出停止查找'''
  • mro列表查找准则:

    1. 子类先查,再查父类

    2. 当继承多个父类的时候,按mro列表顺序被检查

    3. 如果继承多个类,被继承类内具有相同的方法,先输出mro列表左边类的方法

  • 注意:mro列表可以写成 __mro__ 也可以,调用mro方法的必须是起始类,obj是D的对象,所以用D.mro()

  • mro列表是通过一个C3线性算法来实现的

  • 非菱形结构

    代码实现如下:

    '''py3中'''
    
    
    class E:
        pass
    
    
    class F:
        pass
    
    
    class B(E):
        pass
    
    
    class C(F):
        pass
    
    
    class D:
        def test(self):
            print('from D')
    
    
    class A(B, C, D):
        pass
    
    
    print(A.mro())
    '''
    查找顺序如下:
    [<class '__main__.A'>, 
    <class '__main__.B'>, 
    <class '__main__.E'>, 
    <class '__main__.C'>, 
    <class '__main__.F'>, 
    <class '__main__.D'>,
     <class 'object'>]
    '''
    
    obj = A()
    obj.test()  
    # 结果为:from D

    深度优先和广度优先

    深度优先:

  • 经典类:按深度优先查询
  • 经典类查找顺序如下:

    在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):
        pass
    
    
    obj = A()
    obj.test()  # 查找顺序为:obj->A->B->E->G->C->F->D->object
    
    # 结果
    from B

    广度优先:

  • 新式类:按广度优先顺序查找
  • 新式类查找顺序如下:

    在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):
        pass
    
    
    obj = A()
    obj.test() # 查找顺序为:obj->A->B->E->C->F->D->G->object
    
    # 结果
    from D

    python学习资源汇总 需要的伙伴自取腾讯文档-在线PDFhttps://docs.qq.com/pdf/DR1doYmNBYUZ3RVNX

    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):
        pass
    
    
    c = C()
    c.test()
    print(C.mro())
    # 查找顺序如下
    #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
    
    # 结果
    from A
    from B

    方法补充:

    1. sel.__class__ 查看对象所属类

    2. 类名/对象名.__dict__ 查看类/对象名称空间

    3. 类名/对象名.__bases__ 查看父类

    4. 起始类名.__mro__ 打印继承顺序,py3从左到右查找

    5. locals() 查看局部名称空间

    6. globals() 查看全局名称空间

    7. dirs(str) 查看字符串所搭配的内置方法有哪些,查看内容可换

    来源:IT孔乙己

    物联沃分享整理
    物联沃-IOTWORD物联网 » python 继承(史上最详细版本)

    发表评论