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. 如果到最后都没有找到,程序报错

相关文章
|
1月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
158 1
|
1月前
|
算法 Java Docker
(Python基础)新时代语言!一起学习Python吧!(三):IF条件判断和match匹配;Python中的循环:for...in、while循环;循环操作关键字;Python函数使用方法
IF 条件判断 使用if语句,对条件进行判断 true则执行代码块缩进语句 false则不执行代码块缩进语句,如果有else 或 elif 则进入相应的规则中执行
243 1
|
1月前
|
Java 数据处理 索引
(numpy)Python做数据处理必备框架!(二):ndarray切片的使用与运算;常见的ndarray函数:平方根、正余弦、自然对数、指数、幂等运算;统计函数:方差、均值、极差;比较函数...
ndarray切片 索引从0开始 索引/切片类型 描述/用法 基本索引 通过整数索引直接访问元素。 行/列切片 使用冒号:切片语法选择行或列的子集 连续切片 从起始索引到结束索引按步长切片 使用slice函数 通过slice(start,stop,strp)定义切片规则 布尔索引 通过布尔条件筛选满足条件的元素。支持逻辑运算符 &、|。
137 0
|
2月前
|
设计模式 缓存 监控
Python装饰器:优雅增强函数功能
Python装饰器:优雅增强函数功能
264 101
|
2月前
|
缓存 测试技术 Python
Python装饰器:优雅地增强函数功能
Python装饰器:优雅地增强函数功能
202 99
|
2月前
|
存储 缓存 测试技术
Python装饰器:优雅地增强函数功能
Python装饰器:优雅地增强函数功能
184 98
|
2月前
|
缓存 Python
Python中的装饰器:优雅地增强函数功能
Python中的装饰器:优雅地增强函数功能
|
3月前
|
Python
Python 函数定义
Python 函数定义
466 155
|
4月前
|
PHP Python
Python format()函数高级字符串格式化详解
在 Python 中,字符串格式化是一个重要的主题,format() 函数作为一种灵活且强大的字符串格式化方法,被广泛应用。format() 函数不仅能实现基本的插入变量,还支持更多高级的格式化功能,包括数字格式、对齐、填充、日期时间格式、嵌套字段等。 今天我们将深入解析 format() 函数的高级用法,帮助你在实际编程中更高效地处理字符串格式化。
534 0
|
2月前
|
算法 安全 数据安全/隐私保护
Python随机数函数全解析:5个核心工具的实战指南
Python的random模块不仅包含基础的随机数生成函数,还提供了如randint()、choice()、shuffle()和sample()等实用工具,适用于游戏开发、密码学、统计模拟等多个领域。本文深入解析这些函数的用法、底层原理及最佳实践,帮助开发者高效利用随机数,提升代码质量与安全性。
544 0

推荐镜像

更多