python面向对象-继承

一. 继承的概念和实现

1. 概念和语法

class 类名(父类):

说明:

1. 被继承的类放在括号中,B继承了A,则B称为A的子类,A称为B的父类

2. 子类继承父类,默认继承父类所有的属性和方法

3. 在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。

4. 在python中,类支持多继承

2. 示例:

class A(object):
    def __init__(self):
        self.name = "A"

    def fn1(self):
        print("A类方法执行")

class B(A):
    pass

b = B()
print(b.name)   # A
b.fn1()     # A类方法执行

说明:B类继承了A, 就继承了A的所有属性和方法

 二. 多继承

1. 语法:

class 子类(父类1, 父类2,...):
    代码

2. 子类重写父类同名方法和属性

子类使用属性和方法时,首先使用自己的属性和方法,自己没有时,才会去父类中找。

class A(object):
    def __init__(self):
        self.name = "A"

    def fn1(self):
        print("A类方法执行")

class B():
    def __init__(self):
        self.name = "B"
    def fn1(self):
        print("B类的方法")

class C(A, B):
    def __init__(self):
        self.name = "C"

    def fn1(self):
        print("C的方法执行")

cc = C()
print(cc.name)  # C
cc.fn1()    # C的方法执行

三. 多个父类存在同名方法属性时

当多个父类存在同名的属性或方法时,默认按定义的顺序,使用第一个父类的属性方法

class A(object):
    def __init__(self):
        self.name = "A"

    def fn1(self):
        print("A类方法执行")

class B():
    def __init__(self):
        self.name = "B"
    def fn1(self):
        print("B类的方法")

class C(A, B):
    pass

cc = C()
print(cc.name)  # A
cc.fn1()    # A类方法执行

四. 子类调用父类的属性和方法

语法:

父类类名.父类方法(self,其他参数)

 

class A(object):
    def __init__(self):
        self.name = "A"

    def fn1(self):
        print(f"{self.name}类方法执行")

class B():
    def __init__(self):
        self.name = "B"
    def fn2(self):
        print(f"{self.name}类的方法")

class C(A, B):
    def __init__(self):
        self.name = "C"

    def fn1(self):
        A.__init__(self)       #调用父类初始化方法,self显式传递
        A.fn1(self)     # 调用父类方法
        self.__init__()     # 这行如果没有,下面打印中name熟悉值为A
        print(f"{self.name}的方法执行")

cc = C()
cc.fn1()    # C的方法执行

说明:

1. 通过类名调用方法时,self(当前对象)需要显式传递

2. 对象调用方法时,self不需要显式传递,如上面的 self.__init__() ,这个调用相当于对象直接调用

3. 通过self.属性 定义的属性与对象绑定,多次赋值时,后面的赋值覆盖前面的赋值,如上面的例子,父类和子类都有name属性,调用父类的 A.__init__(self) 会重新给name属性赋值,即不管是在子类中还是父类中,self.name操作的是同一个变量name

5. 多层继承

多层继承是指:子类继承父类后,子类也能被其他类继承

class A(object):
    def __init__(self):
        self.name = "A"
        self.a_name = "a_name"

    def fn1(self):
        print("a类fn1方法执行")

    def fn2(self):
        print("a类fn2方法执行")

class B(A):
    def __init__(self):
        self.name = "B"
        self.b_name = "b_name"

    def fn1(self):
        print("b类fn1的方法")

class C(B):
    def __init__(self):
        self.name = "C"


cc = C()
cc.fn1()    # b类fn1的方法
cc.fn2()    # a类fn2方法执行

说明:

1.上面代码有多层继承,C继承B, B继承A

2. 多层继承时,方法或属性的调用会由子类到父类,一层一层往上找。即如果当前类中有,则调用当前类的属性方法,否则去父类中找,没找到则继续往上找,知道找到为止

6. super() 调用父类方法

语法:

super(当前类名, self).父类方法()

super() 中的当前类名,和self 参数可以省略:

super(当前类名, self).父类方法()

 

class A(object):
    def __init__(self):
        self.name = "A"
        self.a_name = "a_name"

    def fn1(self):
        print("a类fn1方法执行")

    def fn2(self):
        print("a类fn2方法执行")

class B(A):
    def __init__(self):
        self.name = "B"
        self.b_name = "b_name"

    def fn1(self):
        print(f"b类fn1的方法, name = {self.name}")

class C(B):
    def __init__(self):
        self.name = "C"
    
    def fn3(self):
        super(C, self).fn1()    # b类fn1的方法, name = C
        super().fn1()           # b类fn1的方法, name = C

cc = C()
cc.fn3()

说明:

super()用于调用当前类的父类的方法,self可省略,省略时会自动传入

7. python中的方法解析顺序(Method Resolution Order,或MRO)

  • MRO,就是方法解析顺序,是类的一个属性
  • MRO在定义类时被计算出来,并保存在类的__mro__属性中。
  • 在继承的情形中,MRO决定了方法(属性)搜索的顺序,最终决定调用哪个类的方法(属性)

对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution Order,或MRO)。对于只支持单继承的语言来说,MRO 一般比较简单;而对于 Python 这种支持多继承的语言来说,MRO 就复杂很多。

1. 查看类的MRO:

inspect.getmro(类名) 方法可以获取指定类的MRO。获取到的为一个元组,元组元素的顺序即为MRO顺序
import inspect


class C(object):
    def dispatch(self):
        print("C中的dispatch")

class D(object):
    pass

class B(D):
    def dispatch(self):
        print("B中的dispatch")
        return super(B, self).dispatch()


class A(B, C):
    pass


print(inspect.getmro(A))        # (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>)
print(inspect.getmro(B))        # (<class '__main__.B'>, <class '__main__.D'>, <class 'object'>)
print(inspect.getmro(C))        # (<class '__main__.C'>, <class 'object'>)

2. 计算MRO的方法

  •  MRO的计算顺序是根据类继承关系经过特殊算法计算得到,可以简单理解为采用从左至右的深度优先遍历,但是如果遍历中出现重复的类,只保留最后一个。如:

上面类结构可以表示为:

 

从A开始,按照深度优先遍历结果为A->B->D->object->C->object ,根据重复的类保留最后一个原则,最终顺序为A->B->D->C->object,这一结果和上面得到的结果一致。其他的类可通过相同方法获取到MRO

3. 方法调用举例

  • 当使用 super(A, self).fn() 或 super().fn() 调用方法时,首先获取到self对象所对应的类的MRO, 找到这个MRO中当前类A所在的位置,从A的下一个节点开始,按照MRO顺序依次搜索方法fn,搜索到的第一个fn方法,即为要调用的方法
import inspect


class C(object):
    def dispatch(self):
        print("C中的dispatch")

class D(object):
    pass

class B(D):
    def dispatch(self):
        print("B中的dispatch")
        return super(B, self).dispatch()


class A(B, C):
    pass


print(inspect.getmro(A))        # A->B->D->C->object

a = A()
a.dispatch()

输出结果:

C:\Users\11265\AppData\Local\Programs\Python\Python39\python.exe C:/Users/11265/Desktop/code/venv/demo.py
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>)
B中的dispatch
C中的dispatch

 

posted @ 2020-12-25 23:21  foreast  阅读(73)  评论(0编辑  收藏  举报