注册 登录
Python基础教程

第一章: 环境搭建,安装Python

第二章: 挑选一款趁手的IDE

第三章: 计算机基础知识

第四章: 命令行基础知识

第五章: 从全局把握Python

第六章: Python语言基础

第七章: Python流程控制

第八章: Python数据类型与运算

第九章: Python字符串类型

第十章: Python列表类型

第十一章: Python元组类型

第十二章: Python字典类型

第十三章: Python集合类型

第十四章: Python函数处理

第十五章: Python文件处理

第十六章: Python面向对象

第十七章: Python异常处理

第十八章: Python模块处理

第十九章: Python高级编程

第二十章: Python项目实战

首页 > Python基础教程 > 第十六章: Python面向对象 > 16.7节: super类型与MRO

16.7节: super类型与MRO

薯条老师 2022-11-28 10:52:49 26303 0

编辑 收藏

广州番禺Python, Java小班周末班培训

薯条老师在广州做Python和Java的小班培训,一个班最多10人,学员的平均就业薪资有11K。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习。培训的课程有Python爬虫,Python后端开发,Python办公自动化,Python大数据分析,Python量化投资,Python机器学习,Java中高级后端开发。授课详情请点击:http://chipscoco.com/?cate=6

16.7.1 什么是super类型?

在16.5节中介绍了super类型。在子类中执行super()方法可以返回一个代理对象,通过该代理对象来执行父类中的方法。

代码实例:
# 定义Cat类,作为父类
class Cat:
    __species = "Cat" 
    
    def __init__(self,name):
       self.__name = name
 
class Babby(Cat):
    def __init__(self, name, age):
        # 执行从父类继承的__init__方法
        super().__init__(name)
        self.age = age
super方法的基本语法:
super(type, arg)
参数type表示子类的类型名,默认为当前子类的类型,参数arg既可以是对象类型,也可以是类类型。如果是对象类型,那么在执行isinstance(arg, type)时,返回值必须为True。如果是类类型,那么在执行issubclass(arg, type)时,返回值必须为True。arg参数无需显式地指定,Python会根据执行的方法类型来自动地传递对应的参数

代码实例:

# __desc__ = 通过super方法来调用父类的方法
 
# 定义Cat类,作为父类
class Cat:
    # 定义类属性species, 表示猫所属的物种
    __species = "Cat" 
 
    @classmethod
    def catch_mice(cls):
        # 不会抓老鼠的猫不是好猫
        print("A {} that doesn't catch a mouse is not a good {}!".format(cls.__species, cls.__species))
 
    def __init__(self, name):
       self.__name = name
 
 
 
# 定Babby类,表示家猫,继承自Cat
class Babby(Cat):
    def __init__(self,name, age):
        super().__init__(name)

        """
        由于调用的是父类中的对象方法,所以执行super().__init__(name)
        相当于调用super(self.__class__, self),Python会自动地传递当前的对象名作为参数
        """
        self.__age = age
 
    @classmethod
    def catch_mice(cls):
        # 执行父类的类方法:catch_mice
        super(Babby, Babby).catch_mice()
    
        """
        也可以直接调用super().catch_mice,Python会根据执行的方法类型来传递对应的参数
        """
      print("Babby is too fat and lazy to catch mice")
 

babby = Babby("Lisa", 18)
babby.catch_mice()
 
"""
程序的输出为:
A cat that doesn't catch a mouse is not a good cat!
Babby is too fat and lazy to catch mice
"""
在super方法super(type, arg)中,如果arg参数为对象类型,那么Python会自动将对象与对象方法进行绑定。同理,如果arg参数为类类型,那么Python会自动将类类型与类方法进行绑定。在进行绑定以后,无需显式地传递对象或类类型作为参数。

16.7.2 方法解析顺序:MRO

super方法返回的是一个代理对象,通过该代理对象可以执行父类中的方法。如果该子类有多个父类,且父类中存在同名的方法,那么Python怎么知道需要调用哪个父类的方法,它是怎么进行方法解析的呢?为了理解Python的内部实现机制,我们需要先掌握一个MRO的概念,MRO的意思为方法解析顺序。在定义类类型时,Python会自动为该类型添加一个__mro__的魔法属性,该属性值是一个元组类型,在元祖中按序保存了当前子类的继承链。

Python通过C3算法将子类的继承链进行线性化,然后写入到__mro__属性中。

代码实例:

# 定义Cat类,作为父类
class Cat:
    # 定义类属性species, 表示猫所属的物种
    __species = "Cat" 
 
    @classmethod
    def catch_mice(cls):
        # 不会抓老鼠的猫不是好猫
        print("A {} that doesn't catch a mouse is not a good {}!".format(cls.__species, cls.__species))
 

# 定义Babby类,继承于Cat
class Babby(Cat):
    pass
 
# 定义Kitty类,继承于Babby
class Kitty(Babby):
    pass
 

# 输出Kitty类中的__mro__
print(Kitty.__mro__)
 
 
"""
程序的输出为:
(<class '__main__.Kitty'>, <class '__main__.Babby'>, <class '__main__.Cat'>, <class 'object'>)
"""
从输出可知,元组的第一个元素为Kitty类型,第二个元素为Babby类型,第三个元素为Cat类型, 第四个元素为object。在Python中,object是所有类型的顶层基类。在子类中执行继承于父类的方法时,Python会从这个mro元祖中进行线性查找,如果mro中的类型包含该方法,就进行调用,并停止查找。继续看代码实例:

# 定义Cat类,作为父类
class Cat:
    # 定义类属性species, 表示猫所属的物种
    __species = "Cat" 
 
    @classmethod
    def catch_mice(cls):
        # 不会抓老鼠的猫不是好猫
        print("A {} that doesn't catch a mouse is not a good {}!".format(cls.__species, cls.__species))
 
 
# 定义Babby类,继承于Cat
class Babby(Cat):
    pass
 
 
class Wildcat(Cat):
    def cry(self):
        print("wildcat never cry for food,they just cry like a baby")
 

# 定义Kitty类,同时继承于Babby和Wildcat
class Kitty(Babby, Wildcat):
    pass
 
 
print(Kitty.__mro__)

"""
输出为:
(<class '__main__.Kitty'>, <class '__main__.Babby'>, <class '__main__.Wildcat'>, <class '__main__.Cat'>, <class 'object'>)
"""
 
 
kitty = Kitty()
kitty.cry()
"""
(1) kitty对象在执行cry方法时,会去Kitty类中的__mro__中进行查找
(2) 如果__mro__中的类型包含该方法,就进行调用,并停止查找
"""
在Python3中,通过C3算法将子类的继承链进行线性化。C3算法利用了拓扑排序的思想,理解C3算法,需要具备数据结构与算法的知识。感兴趣的同学可以在学完Python的基础知识以后,再系统地学习数据结构与算法这门课程。

16.7.3 最具实力的小班培训

薯条老师在广州做Python和Java的小班培训,一个班最多10人。不在广州的同学可以报名线上直播班,跟线下小班的同学们同步学习打算参加小班培训的同学,必须遵守薯条老师的学习安排,认真做作业和项目。把知识学好,学扎实,那么找到一份高薪的工作就是很简单的一件事。

(1) Python后端工程师高薪就业班,月薪11K-18K,免费领取课程大纲
(2) Python爬虫工程师高薪就业班,年薪十五万,免费领取课程大纲
(3) Java后端开发工程师高薪就业班,月薪11K-20K, 免费领取课程大纲
(4) Python大数据分析,量化投资就业班,月薪12K-25K,免费领取课程大纲

扫码免费领取Python学习资料:

关注微信公众号.jpg














欢迎 发表评论:

请登录

忘记密码我要注册

注册账号

已有账号?请登录