想了解Python中的super 函数么

十念  金牌会员 | 2022-9-17 03:27:28 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 567|帖子 567|积分 1701

摘要:经常有朋友问,学 Python 面向对象时,翻阅别人代码,会发现一个 super() 函数,那这个函数的作用到底是什么?
本文分享自华为云社区《Python 中的 super 函数怎么学,怎么解?》,作者:梦想橡皮擦。
实战场景

经常有朋友问,学 Python 面向对象时,翻阅别人代码,会发现一个 super() 函数,那这个函数的作用到底是什么?
super() 函数的用途如下,在子类中调用父类的方法,多用于类的继承关系。
其语法格式如下所示:
  1. super(type[, object-or-type])
复制代码
参数说明如下:

  • type:类,可选参数
  • object-or-type:对象或类,一般为 self,也是可选参数。
返回值是代理对象。
可以直接查询官方帮助手册:
  1. help(super)
复制代码
输出信息如下所示:
  1. Help on class super in module builtins:
  2. class super(object)
  3. |  super() -> same as super(__class__, <first argument>)
  4. |  super(type) -> unbound super object
  5. |  super(type, obj) -> bound super object; requires isinstance(obj, type)
  6. |  super(type, type2) -> bound super object; requires issubclass(type2, type)
  7. |  Typical use to call a cooperative superclass method:
  8. |  class C(B):
  9. |      def meth(self, arg):
  10. |          super().meth(arg)
  11. |  This works for class methods too:
  12. |  class C(B):
  13. |      @classmethod
  14. |      def cmeth(cls, arg):
  15. |          super().cmeth(arg)
复制代码
对输出结果进行分析之后,可以得到如下结论:

  • super 类是一个继承自 object 的类,super() 函数就是对该类的实例化;
  • 调用 super() 实例化之后,返回一个 super 对象;
  • super() 参数有四种搭配,具体看上述输出;
实战编码

单继承使用

直接看一下单继承相关代码,其中使用类名去调用父类方法。
  1. class A:
  2. def funA(self):
  3. print("执行 A ,输出橡皮擦")
  4. class B(A):
  5. def funB(self):
  6. # self 表示 B 类的实例
  7. A.funA(self)
  8. print("执行 B ,输出铅笔")
  9. b = B()
  10. b.funB()
复制代码
上述代码在 B 类中增加了 funB 函数,并且去调用 A 类中的 funA 函数,此时输出的内容如下所示:
  1. 执行 A ,输出橡皮擦
  2. 执行 B ,输出铅笔
复制代码
如果将上述代码修改为 super() 函数调用父类方法,可以使用下述代码:
  1. class A:
  2. def funA(self):
  3. print("执行 A ,输出橡皮擦")
  4. class B(A):
  5. def funB(self):
  6. # 注意 super() 函数的用法
  7. super().funA()
  8. print("执行 B ,输出铅笔")
  9. b = B()
  10. b.funB()
复制代码
上述代码与之前的运行结果一致,在单继承的层级结构中,super 可以直接引用父类,即在子类中不需要使用父类名调用父类方法,而使用 代理对象(super 对象) 去调用,这样的好处就是当父类名改变或继承关系发生改变时,我们不需要对调用进行反复修改。
接下来看一下多继承情况下,super() 函数的实战场景。
  1. class A:
  2. def run(self):
  3. print('AAA')
  4. class B:
  5. def run(self):
  6. print('BBB')
  7. class C:
  8. def run(self):
  9. print('CCC')
  10. class D(A, B, C):
  11. def run(self):
  12. super().run()
  13. d = D()
  14. d.run()
复制代码
此时输出的结果是 AAA,可以看到 super 匹配到的数据是 A 类中的 run 函数,也就是最左侧类中的方法,下面修改一下各类中 run 函数的名称,使其存在差异。
  1. class A:
  2. def run1(self):
  3. print('AAA')
  4. class B:
  5. def run2(self):
  6. print('BBB')
  7. class C:
  8. def run3(self):
  9. print('CCC')
  10. class D(A, B, C):
  11. def run(self):
  12. # 调用 B 中 run2
  13. super().run2()
  14. d = D()
  15. d.run()
复制代码
当一个类继承多个类时,如果第一个父类中没有提供该方法,当前类实例就会通过 __mro__ 属性进行向上搜索,如果到 object 类都没有检索到该方法,就会引发 AttributeError 异常。
基于上述逻辑,我们可以扩展一下,使用 super() 函数中的参数。
  1. class A:
  2. def run(self):
  3. print('AAA')
  4. class B:
  5. def run(self):
  6. print('BBB')
  7. class C:
  8. def run(self):
  9. print('CCC')
  10. class D(A, B, C):
  11. def run(self):
  12. # 调用 C 中 run
  13. super(B, self).run()
  14. d = D()
  15. d.run()
复制代码
此时输出的结果是 CCC,该结果输出表示了使用 super 函数之后,可以使用 super(类,self) 指定以哪个类为起点检索父类中的方法,上述代码设置的 B,就表示从 B 开始检索,后续找到了 C 类,其中包含 run() 方法,所以输出 CCC。
__mro__ 属性的说明。
MRO 是 method resolution order,即方法解析顺序,其本质是继承父类方法时的顺序表。在 Python 中可以使用内置属性 __mro__ 查看方法的搜索顺序,例如下述代码,重点查看输出部分内容。
  1. class A:
  2. def run(self):
  3. print('AAA')
  4. class B:
  5. def run(self):
  6. print('BBB')
  7. class C:
  8. def run(self):
  9. print('CCC')
  10. class D(A, B, C):
  11. def run(self):
  12. # 调用 C 中 run
  13. super(B, self).run()
  14. print(D.__mro__)
复制代码
输出的结果如下所示:
  1. (<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
复制代码
你可以修改一下继承顺序,然后得到不同的输出结果。
  1. (<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
复制代码
在搜索方法的时候,是按照 __mro__ 的输出结果从左到右进行顺序查找的,逻辑如下:
A. 找到方法,停止检索;
B. 没有找到,继续检索下一类;
C. 如果到最后都没有找到,程序报错。
 
点击关注,第一时间了解华为云新鲜技术~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

十念

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表