每次调用父函数或仅在重写函数内部时,我应该使用super()吗?

时间:2015-07-10 08:52:05

标签: python python-3.x

如果我们覆盖父类的方法,我们可以使用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

4 个答案:

答案 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方法时,即使C2B1行为相同,您也会获得不同的结果:

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() 一种方法。不同之处在于,在第一种情况下,您希望在原始实现之前或之后添加额外行为(也称为代码执行),在第二种情况下,您需要完全不同的实现。 您无法在覆盖中使用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,方法mB通过覆盖A来扩展mC扩展{{1}通过覆盖Am生成错误!

修改

我刚才意识到你实际上有两种不同的方法(Dtest_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只是对内存中当前对象的引用。

根据documentationsuper()会导致创建包含其他方法的代理对象。由于这个原因,我认为self将是您的正确方法。