脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Python中的Super用法示例详解

Python中的Super用法示例详解

2022-12-01 10:51Mr-Yang Python

Python中可以直接通过调用父类名调用父类方法,在多重继承中,使用super()是一个很好的习惯,下面这篇文章主要给大家介绍了关于Python中Super用法的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

Python Super用法

这篇文章我们来介绍一下 super,我相信大部分的人使用 super 都是使用这种方式;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 就是我有一个 class 比如说是 Male,然后继承另外一个 class 比如是 Person,然后我在这个 Male 也就是它的子类的 init 函数里面用 super().__init__() 来调用它父类的初识化函数
from objprint import op
class Person:
    def __init__(self, name):
        self.name = name
class Male(Person):
    def __init__(self, name):
        super().__init__(name)
        self.gender = "male"
m = Male('xiaoyang')
op(m)
 
# 输出:
<Male 0x23669a19fa0
  .gender = 'male',
  .name = 'xiaoyang'
>

在我们常用 super 的时候都通常会认为 super 是一个方法或者函数,但是实际上 super 是一个正儿八经的 class,它是一个内置内的名字,然后 super() 并不是调用了一个函数 ,super() 是建立 了一个 super 的对象

?
1
2
>>> type(super)
<class 'type'>

尽管我们更常用的是 super() 括号里面什么都没有,但是 super 的完整版它里面应该是有两个参数,第一个参数是一个 type 也就是一个 class,第二个参数是一个 type 或者是一个 object,其中第二个参数决定了这一个函数绑定到那个 object 或者 class 上,同时第二个参数决定了使用那个 mro,而第一个参数决定了在 mro 链上 从哪个class 开始往后找,例如;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from objprint import op
class Person:
    def __init__(self, name):
        self.name = name
 
class Male(Person):
    def __init__(self, name):
        # super().__init__(name)
        super(Male, self).__init__(name)
        self.gender = "male"
 
m = Male('xiaoyang')
op(m)
 
# 输出:
<Male 0x171f680afa0
  .gender = 'male',
  .name = 'xiaoyang'
>
 
# 其实我们看刚才的 super().__init__(name) 它是等价于 super(Male, self).__init__(name) 的。

那么这个super(Male, self)它是做了这样一个事情,首先它要从 self 这个 object 里面拿到 mro,然后他会找到第一个 argument,也就是 Male 在 mro 里所处的位置,那在当前的情况下 Male 就是最开始的那个(Male Person object)接下来他会从 Male 后面的那个 class 开始找,那它第一个找到的就是 Person,然后它就看Person 里面有没有__init__这个函数,然后发现有这个函数,然后它在把这个__init__绑定到 self 上,在这里可以理解为这个 Person 的__init__函数传进去的这个 self 就是 super 里面的这个 self,也就是说Person.__init__(self,name)这行代码等价于 super(Male, self).__init__(name)这行代码。

至于为什么不直接使用Person.__init__(self,name)是有几个原因:

  • 在未来有可能会改变基类的名字,甚至会改变继承的方式,在这种情况下如果使用 super 的话就什么都不用管,应为他会自动追随这个 mro 找到正确的 class ,但是用这种命名的 class 的话就要全部修改,这样更容易引起错误
  • 其实 super 是动态的,他会根据 self 的 mro 进行寻找,而 self 也就是传进来的这个 argument 它本身是动态的,也就是说同样一个函数里面,我用 super 在不改变这个函数的情况下我有可能会拿到不同的 class。

在来看这个示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from objprint import op
 
class Animal:
    def __init__(self, age):
        self.age = age
 
class Person(Animal):
    def __init__(self, age, name):
        super().__init__(age)
        self.name = name
 
class Male(Person):
    def __init__(self,age, name):
        # super(Male, self).__init__(age, name)
        super(Person, self).__init__(age, name)
        self.gender = "male"
 
m = Male(18'xiaoyang')
op(m)

如果在 Male 中正常的使用它 super(Male, self).__init__(age, name) ,那么它就会正常的初始化所有的东西,它会访问这个 Person 的 __init__ ,然后 Person 的__init__会访问 Animal 的__init__,最后就完成了这个 Male。

那如果把它改成super(Person, self).__init__(age, name) ,那么就会报错,因为当我们使用 super(Person, self)的时候,self 的 mro 链是 Male Person Animal 然后是 object,那第一个参数它由于是 Person,所以他会从 Person 后面的那个 class 也就是 Animal 开始找,那 Animal 是有__init__函数的,但是 Animal 的 __init__ 只有一个参数 age,所以当我们传入 age name 的时候那就错了,这时候就只需要将它改成只传进去一个 age 如: super(Person, self).__init__(age) 就可以了,同时也跳过了 Person。

总结 super 的两个参数也就是第一个 type 和第二个 type 或者 object 分别决定了什么:

第一个只决定了在 mro 这个链上从哪里开始找

第二个是决定使用这个函数的对象和 mro

super 并不是只能在 class 里面使用的,它可以在任何一个地方使用,我只要给定 第二个参数 object 或者 class ,在给定第一个参数从哪里开始找,我就能使用它的函数,例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 那这里的话就是从 m 这个 object 的 mro 上寻找 Male 后面开始的 __init__ 函数,这样实际上就找到了 Person 的 __init__ 函数,然后再用 Person 的 __init__ 函数对 m 这个 object 做初始化
from objprint import op
 
class Animal:
    def __init__(self, age):
        self.age = age
 
class Person(Animal):
    def __init__(self, age, name):
        super().__init__(age)
        self.name = name
 
class Male(Person):
    def __init__(self,age, name):
        super(Person, self).__init__(age)
        self.gender = "male"
 
m = Male(18, 'xiaoyang')
op(m)
 
print("----------------------")
 
super(Male, m).__init__(20, "xiaoyang")
op(m)
 
# 输出:
<Male 0x18412d13f70
  .age = 18,
  .gender = 'male'
>
----------------------
<Male 0x18412d13f70
  .age = 20,
  .gender = 'male',
  .name = 'xiaoyang'
>

附:super的典型用法

很多人对super直观的理解是,调用父类中的方法:

?
1
2
3
4
5
6
7
8
9
10
11
class A:
    def test(self):
        print('A.test')
 
class B(A):
    def test(self):
        super().test()
        print('B.test')
 
b = B()
b.test()


执行结果为:

A.test
B.test

从上面的例子看来,super确实可以调用父类中的方法。但是看下面的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A:
    def test(self):
        print('A.test')
 
class TestMixin:
    def test(self):
        print('TestMixin.test')
        super().test()
 
class B(TestMixin, A):
    def test(self):
        print('B.test')
        super().test()
 
 
b = B()
b.test()

打印结果:

B.test
TestMixin.test
A.test

上面的代码先创建B的对象b,然后调用b.test(),但是B的test函数通过super(),会调到第一个父类TestMixin的test函数,因为TestMixin是B的第一个父类。

TestMixin中的test函数中通过super调到了A中的test函数,但是A不是TestMixin的父类。在这个继承体系中,A和TestMixin都是B的父类,但是A和TestMixin没有任何继承关系。为什么TestMixin中的super会调到A中的test函数呢?

总结 

到此这篇关于Python中Super用法的文章就介绍到这了,更多相关Python Super详解内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/XiaoYang-sir/p/16156355.html

延伸 · 阅读

精彩推荐
  • PythonOpencv-Python图像透视变换cv2.warpPerspective的示例

    Opencv-Python图像透视变换cv2.warpPerspective的示例

    今天小编就为大家分享一篇关于Opencv-Python图像透视变换cv2.warpPerspective的示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋...

    -牧野-5792021-06-15
  • PythonPython栈算法的实现与简单应用示例

    Python栈算法的实现与简单应用示例

    这篇文章主要介绍了Python栈算法的实现与简单应用,简单讲述了栈的原理并结合实例形式给出了基于栈实现的进制转换与括号匹配等相关使用技巧,需要的朋...

    做梦的人-3402020-12-15
  • PythonPython实现的线性回归算法示例【附csv文件下载】

    Python实现的线性回归算法示例【附csv文件下载】

    这篇文章主要介绍了Python实现的线性回归算法,涉及Python使用最小二乘法、梯度下降算法实现线性回归相关算法操作与使用技巧,需要的朋友可以参考下...

    njulpy11762021-05-09
  • Pythonpython字典改变value值方法总结

    python字典改变value值方法总结

    在本文里小编给大家分享了关于python字典如何改变value值的相关知识点以及实例代码,需要的朋友们学习下。...

    脚本之家15822021-07-17
  • PythonPython JSON格式数据的提取和保存的实现

    Python JSON格式数据的提取和保存的实现

    这篇文章主要介绍了Python JSON格式数据的提取和保存的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    mori_d10692021-06-08
  • PythonPython接入MySQL实现增删改查的实战记录

    Python接入MySQL实现增删改查的实战记录

    这篇文章主要给大家介绍了关于Python接入MySQL实现增删改查的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价...

    径流系数5342021-09-15
  • Pythonpandas取出重复数据的方法

    pandas取出重复数据的方法

    今天小编就为大家分享一篇pandas取出重复数据的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    到你了,弟弟4972021-08-01
  • Pythonpython解析xml简单示例

    python解析xml简单示例

    这篇文章主要介绍了python解析xml,结合简单实例形式分析了Python针对城市信息xml文件的读取、解析相关操作技巧,需要的朋友可以参考下...

    轻舞肥羊10202021-07-17