python--super() 函数

简介: python--super() 函数

实战场景

经常有朋友问,学 Python 面向对象时,翻阅别人代码,会发现一个 super() 函数,那这个函数的作用到底是什么?

super() 函数的用途如下,在子类中调用父类的方法,多用于类的继承关系。

其语法格式如下所示:

super(type[, object-or-type])
复制代码

参数说明如下:

  • type:类,可选参数
  • object-or-type:对象或类,一般为 self,也是可选参数。

返回值是代理对象。

可以直接查询官方帮助手册:

help(super)
复制代码

输出信息如下所示:

Help on class super in module builtins:
class super(object)
 |  super() -> same as super(__class__, <first argument>)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super().meth(arg)
 |  This works for class methods too:
 |  class C(B):
 |      @classmethod
 |      def cmeth(cls, arg):
 |          super().cmeth(arg)
复制代码

对输出结果进行分析之后,可以得到如下结论:

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

实战编码

单继承使用

直接看一下单继承相关代码,其中使用类名去调用父类方法。

class A:
    def funA(self):
        print("执行 A ,输出橡皮擦")
class B(A):
    def funB(self):
        # self 表示 B 类的实例
        A.funA(self)
        print("执行 B ,输出铅笔")
b = B()
b.funB()
复制代码

上述代码在 B 类中增加了 funB 函数,并且去调用 A 类中的 funA 函数,此时输出的内容如下所示:

执行 A ,输出橡皮擦
执行 B ,输出铅笔
复制代码

如果将上述代码修改为 super() 函数调用父类方法,可以使用下述代码:

class A:
    def funA(self):
        print("执行 A ,输出橡皮擦")
class B(A):
    def funB(self):
        # 注意 super() 函数的用法
        super().funA()
        print("执行 B ,输出铅笔")
b = B()
b.funB()
复制代码

上述代码与之前的运行结果一致,在单继承的层级结构中,super 可以直接引用父类,即在子类中不需要使用父类名调用父类方法,而使用 代理对象(super 对象) 去调用,这样的好处就是当父类名改变或继承关系发生改变时,我们不需要对调用进行反复修改。


接下来看一下多继承情况下,super() 函数的实战场景。


class A:
    def run(self):
        print('AAA')
class B:
    def run(self):
        print('BBB')
class C:
    def run(self):
        print('CCC')
class D(A, B, C):
    def run(self):
        super().run()
d = D()
d.run()

此时输出的结果是 AAA,可以看到 super 匹配到的数据是 A 类中的 run 函数,也就是最左侧类中的方法,下面修改一下各类中 run 函数的名称,使其存在差异。

class A:
    def run1(self):
        print('AAA')
class B:
    def run2(self):
        print('BBB')
class C:
    def run3(self):
        print('CCC')
class D(A, B, C):
    def run(self):
        # 调用 B 中 run2
        super().run2()
d = D()
d.run()

当一个类继承多个类时,如果第一个父类中没有提供该方法,当前类实例就会通过 __mro__ 属性进行向上搜索,如果到 object 类都没有检索到该方法,就会引发 AttributeError 异常。

基于上述逻辑,我们可以扩展一下,使用 super() 函数中的参数。

class A:
    def run(self):
        print('AAA')
class B:
    def run(self):
        print('BBB')
class C:
    def run(self):
        print('CCC')
class D(A, B, C):
    def run(self):
        # 调用 C 中 run
        super(B, self).run()
d = D()
d.run()
复制代码

此时输出的结果是 CCC,该结果输出表示了使用 super 函数之后,可以使用 super(类,self) 指定以哪个类为起点检索父类中的方法,上述代码设置的 B,就表示从 B 开始检索,后续找到了 C 类,其中包含 run() 方法,所以输出 CCC。


__mro__ 属性的说明。


MRO 是 method resolution order,即方法解析顺序,其本质是继承父类方法时的顺序表。

在 Python 中可以使用内置属性 __mro__ 查看方法的搜索顺序,例如下述代码,重点查看输出部分内容。

class A:
    def run(self):
        print('AAA')
class B:
    def run(self):
        print('BBB')
class C:
    def run(self):
        print('CCC')
class D(A, B, C):
    def run(self):
        # 调用 C 中 run
        super(B, self).run()
print(D.__mro__)
复制代码

输出的结果如下所示:

 (<class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)


你可以修改一下继承顺序,然后得到不同的输出结果。

(<class '__main__.D'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.B'>, <class 'object'>)

在搜索方法的时候,是按照 __mro__ 的输出结果从左到右进行顺序查找的,逻辑如下:

A. 找到方法,停止检索;

B. 没有找到,继续检索下一类;

C. 如果到最后都没有找到,程序报错

相关文章
|
2月前
|
Python
【python从入门到精通】-- 第五战:函数大总结
【python从入门到精通】-- 第五战:函数大总结
80 0
|
20天前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
124 67
|
14天前
|
Python
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
42 18
|
6天前
|
数据可视化 DataX Python
Seaborn 教程-绘图函数
Seaborn 教程-绘图函数
36 8
|
15天前
|
Python
Python中的函数
Python中的函数
31 8
|
22天前
|
监控 测试技术 数据库
Python中的装饰器:解锁函数增强的魔法####
本文深入探讨了Python语言中一个既强大又灵活的特性——装饰器(Decorator),它以一种优雅的方式实现了函数功能的扩展与增强。不同于传统的代码复用机制,装饰器通过高阶函数的形式,为开发者提供了在不修改原函数源代码的前提下,动态添加新功能的能力。我们将从装饰器的基本概念入手,逐步解析其工作原理,并通过一系列实例展示如何利用装饰器进行日志记录、性能测试、事务处理等常见任务,最终揭示装饰器在提升代码可读性、维护性和功能性方面的独特价值。 ####
|
29天前
|
Python
Python中的`range`函数与负增长
在Python中,`range`函数用于生成整数序列,支持正向和负向增长。本文详细介绍了如何使用`range`生成负增长的整数序列,并提供了多个实际应用示例,如反向遍历列表、生成倒计时和计算递减等差数列的和。通过这些示例,读者可以更好地掌握`range`函数的使用方法。
45 5
|
2月前
|
Python
Python之函数详解
【10月更文挑战第12天】
Python之函数详解
|
2月前
|
存储 数据安全/隐私保护 索引
|
1月前
|
测试技术 数据安全/隐私保护 Python
探索Python中的装饰器:简化和增强你的函数
【10月更文挑战第24天】在Python编程的海洋中,装饰器是那把可以令你的代码更简洁、更强大的魔法棒。它们不仅能够扩展函数的功能,还能保持代码的整洁性。本文将带你深入了解装饰器的概念、实现方式以及如何通过它们来提升你的代码质量。让我们一起揭开装饰器的神秘面纱,学习如何用它们来打造更加优雅和高效的代码。