Python 入门 16 —— 类的多态、 MRO列表、 super()函数

一、多态

当多个子类继承同一个父类时,在各个子类中都可以重载父类的成员。通过各自的重载,父类的某一成员在不同的子类中就会有不同的“表现”,这种现象就叫“多态”。例如:

class b01: x=0

class cls01(b01):x=11
class cls02(b01):x=22
class cls03(b01):x=33
class cls04(b01):x=44
class cls05(b01):x=55

print(cls01.x, cls02.x, cls03.x, cls04.x, cls05.x)    # 11 22 33 44 55

以上例子中基类中定义的变量 x,当用不同的子类中,其值各不相同,这就是典型的“多态”现象。不过,以上例子展示的是最简单的多态形式。在实际的子类重载父类成员的过程上,通常都会引用父类的成员,即,父类已有的功能不再重复实现。

在派生类中引用基类成员可以有两种方法:一是用“基类名.成员名”的方法;二是用“super().成员名”的方法。用“基类名.成员名”的方法虽然简单明了,但潜在一个问题:当基类名发生改变时,子类就必须同时进行修改————逐一地在引用基类成员的地方将旧的基类名修改为新的基类名。而用“super().成员名”的方法就可以有效地避免这个问题,所以,“super().成员名”是最常使用的方法。

因为super()函数是依据 MRO列表来运行的,所以要学习super()函数,就需要先了解 MRO列表。

二、MRO列表

MRO(method resolution order),直译:方法解析顺序,即一个描述类的继承关系的列表。每个类在定义之后,Python 运行程序都会依据其继承关系,遵循以下规则计算出 MRO列表,并存放在类的内部。

1、对于单继承,列表中的顺序为:派生类、基类、基类的基类 ······
2、对于多继承,列表中的顺序为:派生类、(第一个基类的 MRO列表)、(第二个基类的 MRO列表) ······

类的 MRO列表,可以通过 print(类名.mro()) 或 print(类名.mro) 的方法查看。例如:

# 示例一:单继承

class c1:pass
class c2(c1):pass
class c3(c2):pass
class c4(c3):pass

print(c4.mro())
# 显示:
[<class '__main__.c4'>, <class '__main__.c3'>, <class '__main__.c2'>, <class '__main__.c1'>, <class
'object'>]

# 即顺序为: c4 ———— c3 ———— c3 ———— c1

#示例二:多继承

class c111:pass
class c112:pass
class c11(c111,c112):pass

class c12:pass

class c1(c11,c12):pass

class c2:pass

class c31:pass
class c3(c31):pass

class c0(c1,c2,c3):pass

print(c0.mro())
# 显示:
[<class '__main__.c0'>, <class '__main__.c1'>, <class '__main__.c11'>, <class '__main__.c111'>, <cla
ss '__main__.c112'>, <class '__main__.c12'>, <class '__main__.c2'>, <class '__main__.c3'>, <class '_
_main__.c31'>, <class 'object'>]

# 即顺序为:c0 ———— c1 ———— c11 ———— c111 ———— c112 ———— c12 ———— c2 ———— c3 ———— c31

三、super()函数

super(type, obj)
typy ———— 类名
obj ———— 必须是第一个参数 type 的子类或子类的对象
返回值 ———— 查看第二个参数 obj 的 MRO列表,即继承顺序,找到紧跟在 type 对应的类之后一个类,并返回。

第一、因为函数的第一步是要在第二个参数 obj 的 MRO列表上找与第一个参数 type 对应的类,所以,obj 必须是 type 的子类或子类对象,以确保 type 在 obj 的 MRO列表上。

第二、返回值是 MRO列表上紧跟在 type 后面的那个类,这个类可能是 type 的父类,可能是 type 的兄弟类,也可能什么也不是。只有在完全单类继承的情况下,返回值才一定是 type 的父类。如果 type 已经是MRO列表上的最后一个类,也就是在 type 不再有类,则报错。

第三、当两个参数都为空时,即super(),返回当前对象对应的类的第一个基类。

例如:

class c111:x=111
class c112:x=112
class c11(c111,c112):x=11

class c12:x=12
class c1(c11,c12):x=1

class c2:x=2

class c31:x=31
class c3(c31):x=3

class c0(c1,c2,c3):
    def fun(self):
        print(super(c0,c0).x,end='----')
        print(super(c1,c0).x,end='----')
        print(super(c11,c0).x,end='----')
        print(super(c111,c0).x,end='----')
        print(super(c112,c0).x,end='----')
        print(super(c12,c0).x,end='----')
        print(super(c2,c0).x,end='----')
        print(super(c3,c0).x)

    def fun2(self):
        print(super().x)

print(c0.mro())
# 显示:
[<class '__main__.c0'>, <class '__main__.c1'>, <class '__main__.c11'>, <class '__main__.c111'>, <cla
ss '__main__.c112'>, <class '__main__.c12'>, <class '__main__.c2'>, <class '__main__.c3'>, <class '_
_main__.c31'>, <class 'object'>]

# 即顺序为:c0 ———— c1 ———— c11 ———— c111 ———— c112 ———— c12 ———— c2 ———— c3 ———— c31

c0.fun(0)   # 1--11--111--112--12--2--3--31

obj01=c0()
obj01.fun2()    # 1

———————————————— 本篇完 ————————————————

看完之后,麻烦您顺手点击下方 “点赞” 两个字给我点个赞吧 ^-^ , 谢谢您了。

如果您还能像我小学一年级班主任好老师那样,给我随心写上几句表扬或批评的话语,那真是感激不尽!

在我人生的道路上,有了您的鼓励和指导,我一定成长快快。

发布了28 篇原创文章 · 获赞 6 · 访问量 2272

猜你喜欢

转载自blog.csdn.net/Jeff888999/article/details/104070197