如果我们覆盖父类的方法,我们可以使用super()
来避免提及父类的名称 - 这很清楚。
但是,当我们在子类中使用父类中定义的某些函数时呢?什么是优选方式:使用super().parent_method()
或self.parent_method()
?或者没有区别?
class A:
def test1(self):
pass
def test_a(self):
pass
class B(A):
def test1(self):
super().test1() # That's clear.
def test_b(self):
# Which option is better, when I want to use parent's func here?
# 1) super().test_a()
# 2) self.test_a()
pass
答案 0 :(得分:2)
通常,您需要使用self.test_a()
来调用继承的方法。但是,在某些罕见的情况下,您可能希望使用super().test_a()
,即使它似乎也做同样的事情。它们不是等价的,即使它们在你的例子中有相同的行为。
为了探索这些差异,让我们制作两个版本的B
类,每个版本调用一次,然后创建两个C
类,进一步扩展B
类并覆盖{ {1}}:
test_a
当您在class A(object):
def test_a(self):
return "A"
class B1(A):
def test_b(self):
return self.test_a() + "B"
class B2(A):
def test_b(self):
return super().test_a() + "B"
class C1(B1):
def test_a(self):
return "C"
class C2(B2):
def test_a(self):
return "C"
和test_b()
个实例上调用C1
方法时,即使C2
和B1
行为相同,您也会获得不同的结果:
B2
这是因为>>> B1().test_b()
'AB'
>>> B2().test_b()
'AB'
>>> C1().test_b()
'CB'
>>> C2().test_b()
'AB'
中的super()
调用告诉Python您要在任何更多派生类中跳过B2.test_b
的版本,并始终从父类调用实现。 (实际上,我认为它可能是多重继承情况下的兄弟级别,但这种情况变得更加模糊。)
就像我在顶部说的那样,你通常希望允许像test_a
这样更派生的类来覆盖你在较少派生类中调用的继承方法的行为。这意味着大部分时间使用C
都是可行的方法。当你做一些奇特的事情时,你只需要使用self.whatever
。
答案 1 :(得分:1)
由于B
是 A
,因此它有一个成员test_a
。所以你称之为
self.test_a()
B
不覆盖A.test_a
,因此无需使用super()
来调用它。
由于B
会覆盖 A.test1
,您必须明确指定要调用的方法。
self.test1()
将调用B.test1
,而
super().test1()
将致电A.test1
。
答案 2 :(得分:1)
如果我们覆盖父类的方法,我们可以使用super()来避免 提到父母的名字 - 这很清楚。
实际上super()
不是语法糖,其目的是调用某个方法的父实现。
如果您想要覆盖父方法,则必须使用super()
,而不想在覆盖}时使用super()
1}}强>一种方法。不同之处在于,在第一种情况下,您希望在原始实现之前或之后添加额外行为(也称为代码执行),在第二种情况下,您需要完全不同的实现。
您无法在覆盖中使用self.method_name()
,结果将是递归错误! (RuntimeError: maximum recursion depth exceeded
)
示例:
class A:
def m(self):
print('A.m implementation')
class B(A):
def m(self):
super().m()
print('B.m implementation')
class C(A):
def m(self):
print('C.m implementation')
class D(A):
def m(self):
self.m()
a = A()
a.m()
b = B()
b.m()
c = C()
c.m()
d = D()
d.m()
给定基类A
,方法m
,B
通过覆盖A
来扩展m
,C
扩展{{1}通过覆盖A
,m
生成错误!
修改强>
我刚才意识到你实际上有两种不同的方法(D
和test_a
)。我的回答仍然有效,但就您的具体情况而言:
您应该使用test_b
,除非您在B类中覆盖/覆盖该方法并且您想要执行原始实现...所以我们可以说调用self.test_a()
或super().test_a()
它是相同的,因为你永远不会覆盖/覆盖子类中的原始self.test_a()
...但如果不是覆盖/覆盖,则使用test_a()
是无意义的/ p>
答案 3 :(得分:1)
首先,super().test_a()
和self.test_a()
两种方式都会导致执行方法test_a()
。
由于Class B
没有覆盖或覆盖test_a()
,我认为使用self.test_a()
会非常有效,因为self只是对内存中当前对象的引用。
根据documentation,super()
会导致创建包含其他方法的代理对象。由于这个原因,我认为self
将是您的正确方法。