Python中的super()如何使用

写在前面

我们在使用 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'。这里没有设置var1var2的值,因为你从未初始化 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))来调用父函数,并根据其优点选择其中之一。

希望这个解答对你有所帮助!如果你还有其他问题,请随时提问。


原文始发于微信公众号(harvey的网络日志):Python中的super()如何使用

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/231107.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!