Python高级语法3:方法解析顺序表MRO

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析DNS,个人版 1个月
全局流量管理 GTM,标准版 1个月
简介: Python高级语法3:方法解析顺序表MRO

一、多继承以及MRO顺序



  • 1.1、单独调用父类的方法: 父类名.__init__(self, 参数):不建议使用,父类的父类可能被调用多次


class Parent(object):
def __init__(self, name):
     print('parent的init开始被调用')
     self.name = name
     print('parent的init结束被调用')
class Son1(Parent):
     def __init__(self, name, age):
          print('Son1的init开始被调用')
          self.age = age
          Parent.__init__(self, name)
          print('Son1的init结束被调用')
class Son2(Parent):
     def __init__(self, name, gender):
          print('Son2的init开始被调用')
          self.gender = gender
          Parent.__init__(self, name)
          print('Son2的init结束被调用')
class Grandson(Son1, Son2):
     def __init__(self, name, age, gender):
          print('Grandson的init开始被调用')
          Son1.__init__(self, name, age)  # 单独调用父类的初始化方法
          Son2.__init__(self, name, gender)
          print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用类名.__init__ 发生的状态******\n\n")
print(Grandson.__mro__)
  • 执行的结果:


Grandson的init开始被调用
Son1的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用类名.__init__ 发生的状态******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
  • 1.2、多继承中super调用有所父类的被重写的方法:super().__init__(self, 参数)


print("******多继承使用super().__init__ 发生的状态******")
class Parent(object):
      def __init__(self, name, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
           print('parent的init开始被调用')
           self.name = name
           print('parent的init结束被调用')
class Son1(Parent):
      def __init__(self, name, age, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
          print('Son1的init开始被调用')
          self.age = age
          super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
          print('Son1的init结束被调用')
class Son2(Parent):
      def __init__(self, name, gender, *args, **kwargs):  # 为避免多继承报错,使用不定长参数,接受参数
           print('Son2的init开始被调用')
           self.gender = gender
           super().__init__(name, *args, **kwargs)  # 为避免多继承报错,使用不定长参数,接受参数
           print('Son2的init结束被调用')
class Grandson(Son1, Son2):
      def __init__(self, name, age, gender):
            print('Grandson的init开始被调用')
            # 多继承时,相对于使用类名.__init__方法,要把每个父类全部写一遍
            # 而super只用一句话,执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因
            # super(Grandson, self).__init__(name, age, gender)
            super().__init__(name, age, gender)
            print('Grandson的init结束被调用')
            print(Grandson.__mro__)
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
print('性别:', gs.gender)
print("******多继承使用super().__init__ 发生的状态******\n\n")
  • 运行结果:


******多继承使用super().__init__ 发生的状态******
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandson的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用
parent的init结束被调用
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名: grandson
年龄: 12
性别: 男
******多继承使用super().__init__ 发生的状态******


  • 注意:


  • 以上2个代码执行的结果不同
  • 如果2个子类中都继承了父类,当在子类中通过父类名调用时,parent被执行了2次
  • 如果2个子类中都继承了父类,当在子类中通过super调用时,parent被执行了1次
  • 1.3、单继承中super


print("******单继承使用super().__init__ 发生的状态******")
class Parent(object):
     def __init__(self, name):
          print('parent的init开始被调用')
          self.name = name
          print('parent的init结束被调用')
class Son1(Parent):
    def __init__(self, name, age):
          print('Son1的init开始被调用')
          self.age = age
          super().__init__(name)  # 单继承不能提供全部参数
          print('Son1的init结束被调用')
class Grandson(Son1):
    def __init__(self, name, age, gender):
          print('Grandson的init开始被调用')
          super().__init__(name, age)  # 单继承不能提供全部参数
          print('Grandson的init结束被调用')
gs = Grandson('grandson', 12, '男')
print('姓名:', gs.name)
print('年龄:', gs.age)
#print('性别:', gs.gender)
print("******单继承使用super().__init__ 发生的状态******\n\n")


  • 1.4、总结
  • (1)、super().init相对于类名.init,在单继承上用法基本无差
  • (2)、但在多继承上有区别,super方法能保证每个父类的方法只会执行一次,而使用类名的方法会导致方法被执行多次,具体看前面的输出结果
  • (3)、多继承时,使用super方法,对父类的传参数,应该是由于python中super的算法导致的原因,必须把参数全部传递,否则会报错
  • (4)、单继承时,使用super方法,则不能全部传递,只能传父类方法所需的参数,否则会报错
  • (5)、多继承时,相对于使用类名.init方法,要把每个父类全部写一遍, 而使用super方法,只需写一句话便执行了全部父类的方法,这也是为何多继承需要全部传参的一个原因


  • 1.5、面试题:以下的代码的输出将是什么? 说出你的答案并解释。


class Parent(object):
       x = 1
class Child1(Parent):
       pass
class Child2(Parent):
       pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
  • 答案, 以上代码的输出是:


1 1 1
 1 2 1
 3 2 3


  • 使你困惑或是惊奇的是关于最后一行的输出是 3 2 3 而不是 3 2 1。为什么改变了 Parent.x 的值还会改变 Child2.x 的值,但是同时 Child1.x 值却没有改变?
  • 这个答案的关键是,在 Python 中,类变量在内部是作为字典处理的。如果一个变量的名字没有在当前类的字典中发现,将搜索祖先类(比如父类)直到被引用的变量名被找到(如果这个被引用的变量名既没有在自己所在的类又没有在祖先类中找到,会引发一个 AttributeError 异常)。
  • 因此,在父类中设置 x = 1 会使得类变量 x 在引用该类和其任何子类中的值为 1。这就是因为第一个 print 语句的输出是 1 1 1。
  • 随后,如果任何它的子类重写了该值(例如,我们执行语句 Child1.x = 2),然后,该值仅仅在子类中被改变。这就是为什么第二个 print 语句的输出是 1 2 1。
  • 最后,如果该值在父类中被改变(例如,我们执行语句 Parent.x = 3),这个改变会影响到任何未重写该值的子类当中的值(在这个示例中被影响的子类是 Child2)。这就是为什么第三个 print 输出是 3 2 3。
目录
相关文章
|
16天前
|
JSON 测试技术 API
Python开发解析Swagger文档小工具
文章介绍了如何使用Python开发一个解析Swagger文档的小工具,该工具可以生成符合httprunner测试框架的json/yaml测试用例,同时还能输出Excel文件,以方便测试人员根据不同需求使用。文章提供了详细的开发步骤、环境配置和使用示例,并鼓励读者为该开源项目贡献代码和建议。
20 1
Python开发解析Swagger文档小工具
|
16天前
|
测试技术 Python
python自动化测试中装饰器@ddt与@data源码深入解析
综上所述,使用 `@ddt`和 `@data`可以大大简化写作测试用例的过程,让我们能专注于测试逻辑的本身,而无需编写重复的测试方法。通过讲解了 `@ddt`和 `@data`源码的关键部分,我们可以更深入地理解其背后的工作原理。
16 1
|
17天前
|
网络协议 API 开发者
Python中的会话管理:requests.Session深度解析
Python中的会话管理:requests.Session深度解析
|
22天前
|
安全 数据库连接 数据库
Python深度解析:上下文协议设计与应用技巧
在Python编程中,资源管理是一个常见且重要的问题。无论是文件操作、网络连接还是数据库事务,都需要确保资源在使用后能够正确地释放或恢复到初始状态。Python通过上下文管理器提供了一种优雅的方式来处理资源的获取与释放,使得代码更加简洁、安全。
|
26天前
|
开发者 Python
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
深入解析Python `httpx`源码,探索现代HTTP客户端的秘密!
60 1
|
26天前
|
开发者 Python
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
深入解析Python `requests`库源码,揭开HTTP请求的神秘面纱!
100 1
|
8天前
|
机器学习/深度学习 数据采集 自然语言处理
Python中实现简单的文本情感分析未来触手可及:新技术趋势与应用深度解析
【8月更文挑战第30天】在数字化的今天,理解和分析用户生成的内容对许多行业至关重要。本文将引导读者通过Python编程语言,使用自然语言处理(NLP)技术,构建一个简单的文本情感分析工具。我们将探索如何利用机器学习模型来识别和分类文本数据中的情感倾向,从而为数据分析和决策提供支持。文章将涵盖从数据预处理到模型训练和评估的全过程,旨在为初学者提供一个易于理解且实用的入门指南。
|
9天前
|
机器学习/深度学习 计算机视觉 Python
深度学习项目中在yaml文件中定义配置,以及使用的python的PyYAML库包读取解析yaml配置文件
深度学习项目中在yaml文件中定义配置,以及使用的python的PyYAML库包读取解析yaml配置文件
23 0
|
23天前
|
Python
深入解析 Python中的命名空间和作用域并举例
【8月更文挑战第15天】Python中的命名空间与作用域是理解变量组织与访问的核心。命名空间是名称到对象的映射,分为全局、局部和内置三种。作用域定义变量的可访问范围,遵循LEGB规则:局部(L)、闭包(E)、全局(G)、内置(B)。示例展示了如何通过`nonlocal`声明跨作用域修改变量。这些机制确保了变量的有效管理和代码的高效执行。
32 0
|
25天前
|
SQL 分布式计算 算法
【python】python指南(二):命令行参数解析器ArgumentParser
【python】python指南(二):命令行参数解析器ArgumentParser
26 0
下一篇
DDNS