我们在使用 Python 进行面向对象编程时可能会遇到一个函数super(),那么它是什么?在类继承中它又起到了什么作用呢?今天这篇文章将带你走近Python的super()函数。
什么是super()函数?
Python 中的super()函数允许子类将任务委托给它的父类或祖先树中的某个类。使用语法是super().method_name(args)。
下面通过两段代码来展示单继承中如何使用super()。
案例1
class ClassOne:
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def add_vars(self):
return self.var1 + self.var2
class ClassTwo(ClassOne):
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
在这里,ClassTwo 继承自 ClassOne。现在让我们创建一个ClassTwo的对象。
由于它继承自ClassOne,如果我们调用ctwo.add_vars(),会发生什么?
two = ClassTwo(3,4)
# 会发什么什么呢?
two.add_vars()
如果你认为结果会导致错误,那么你是正确的。它会返回AttributeError: 'ClassTwo' object has no attribute 'var1'。这里没有设置var1和var2的值,因为你从未初始化 ClassOne。
案例2
class ClassOne:
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def add_vars(self):
return self.var1 + self.var2
class ClassTwo(ClassOne):
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
# 我们增加了这行代码
super().__init__(v1, v2)
在这个案例中,如果你创建一个名为ctwo = ClassTwo(3,4)的ClassTwo对象,然后调用ctwo.add_vars(),它将返回7。这就是super()函数的简单用法。它会委托给实例祖先树中的函数。
two = ClassTwo(3,4)
two.add_vars()
结果:
7
注意!!!
如果你将super().__init__(v1,v2)修改为ClassOne.__init__(self,v1,v2),它也会起到同样的作用。
但是调用super()更好,因为你不需要指定委托类的名称。它是一个计算得出的间接引用。如果明天有人更改了被委托类的名称,你的代码仍然可以正常工作。
多重继承
在多重继承的情况下,处理super()会有点麻烦,而方法解析顺序__mro__的作用就显现出来了。
考虑下面的例子,我们有一个类 Three 继承自两个类 One 和 Two。
class One:
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def add_var(self):
return self.var1 + self.var2
class Two:
def __init__(self, var3, var4):
self.var3 = var3
self.var4 = var4
def add_var_2(self):
return self.var3 + self.var4
class Three(One,Two):
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
super().__init__(v1, v2)
现在假设我们创建一个名为three = Three(3,4)的 Three 类的对象。如果我们调用three.add_var()和three.add_var_2()会发生什么?第一个调用会返回7,而第二个调用会返回AttributeError: 'Three' object has no attribute 'var3'。
这是因为 Three 的__mro__是[Three, One, Two],你可以使用print(Three.__mro__)命令打印出来。通常,MRO 是使用 C3 算法计算的。
那么我们如何让three.add_var_2()成功调用呢?
我最初考虑的是调用两次super(),但实际上并不起作用。它只会按照 MRO 的顺序到达 Class One ,然后停止。
为此我想到了上一章的问题,我们可以显式的初始化每一个父类,如下所示。
class One:
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
def add_var(self):
return self.var1 + self.var2
class Two:
def __init__(self, var3, var4):
self.var3 = var3
self.var4 = var4
def add_var_(self):
return self.var3 + self.var4
class Three(One,Two):
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
One.__init__(self, v1, v2)
Two.__init__(self, v1, v2)
现在,如果你使用three = Three(3,4)创建一个对象,然后调用three.add_var()或three.add_var_2(),它每次都会返回7,而且没有错误。
当我对我发现的解决方案感到高兴时,我在 stackoverflow 上找到了一个帖子。它说父类也应该调用super(),以确保与子类协同工作。
在父类中使用super()的代码如下所示:
class One:
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
# 增加的代码
super().__init__(var1, var2)
def add_var(self):
return self.var1 + self.var2
class Two:
def __init__(self, var3, var4):
self.var3 = var3
self.var4 = var4
# 增加的代码
super().__init__()
def add_var_(self):
return self.var3 + self.var4
class Three(One,Two):
def __init__(self, v1, v2):
self.v1 = v1
self.v2 = v2
# 修改的部分
super().__init__(v1,v2)
在类 One 中,我们必须通过super().__init__传递变量,而在类 Two 中则不必。这是因为 MRO(方法解析顺序)是[Three, One, Two],所以 One 的__init__调用了 Two 的__init__,而 Two 的__init__调用了所有类的根类,它不需要任何变量。此外,如果你传递了变量,会导致错误。
这意味着,如果你想以协同类的方式调用super()函数,我们必须了解它在子类中的使用方式(至少在上面的例子中是如此)。
写在最后
总之,作为开发人员,必须了解这两种使用方式。根据实际需求选用ParentClass.function_name(self,*(args))或者使用super().function_name(*(args))来调用父函数,并根据其优点选择其中之一。
以上就是“Python教程:Python中的super()如何使用”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/11862/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料
查 看2022高级编程视频教程免费获取