【问题标题】:Calling super().method() vs. BaseClass.method(self)调用 super().method() 与 BaseClass.method(self)
【发布时间】:2021-07-18 02:32:00
【问题描述】:

派生类调用基类的方法主要有两种方式。

Base.method(self):

class Derived(Base):
    def method(self):
        Base.method(self)
        ...

super().method():

class Derived(Base):
    def method(self):
        super().method()
        ...

假设我现在这样做:

obj = Derived()
obj.method()

据我所知,Base.method(self)super().method() 都做同样的事情。两者都会调用Base.method 并引用obj。特别是,super() 没有做任何事来实例化Base 类型的对象。相反,它会创建一个super 类型的新对象并将obj 中的实例属性移植到它上面,然后当您尝试从超级对象中获取它时,它会动态地从Base 中查找正确的属性。

super() 方法的优点是在更改派生类的基类时需要做的工作最少。另一方面,Base.method 使用的魔法更少,并且当一个类从多个基类继承时可能更简单、更清晰。

我看到的大多数讨论都建议调用super(),但这是 Python 编码人员的既定标准吗?还是这两种方法都在实践中广泛使用?例如,this stackoverflow question 的答案是双向的,但通常使用super() 方法。另一方面,我这学期教的Python textbook只显示了Base.method的方法。

【问题讨论】:

  • Base.method(self) 也没有执行实例化Base 类型的对象。
  • @martineau 我同意。我只是指出super() 只做了这么多魔术。它为您提供了一个对象,因此您可以调用sup_obj.method() 而不是sup_obj.method(self),但sup_obj 不是Base 的完整实例。即,您不能假设 super() 通过为您提供 Base 的实例来为您提供超级稳健的行为;相反,它只是为您提供了一种在父类中查找方法的方法,这与调用 Base.method(self, ...) 没有太大区别。
  • 我认为使用 super() 更好,因为它可以很好地处理 MRO,更多信息 multiple inheritance 在此处阅读 super 和 mro 部分
  • 从代码可维护性的角度来看,super() 更好。也许您决定要更改继承。例如你有class A(B),你用直接方法把它改成class C(B)class A(C),你跳过C,但是用super你只需打电话给父母。我想这取决于。您想拨打my parent class 还是拨打Base?一种是绝对的,一种是间接的。
  • 除了正确处理多重继承,我喜欢使用super(),因为这意味着不需要将基类名称硬编码到子类中——因此它消除了代码依赖。

标签: python python-3.x class oop inheritance


【解决方案1】:

使用super() 意味着下面的任何内容都应该委托给基类,无论它是什么。这是关于语句的语义。另一方面,明确引用 Base 传达了这样一种想法:Base 是出于某种原因(读者可能不知道)而被明确选择的,这也可能有其应用。

除此之外,使用super() 还有一个非常实际的原因,即协作多重继承。假设您设计了以下类层次结构:

class Base:
    def test(self):
        print('Base.test')

class Foo(Base):
    def test(self):
        print('Foo.test')
        Base.test(self)

class Bar(Base):
    def test(self):
        print('Bar.test')
        Base.test(self)

现在您可以同时使用 FooBar 并且一切正常。然而,这两个类不能在多重继承模式中一起工作:

class Test(Foo, Bar):
    pass

Test().test()
# Output:
# Foo.test
# Base.test

最后一次调用test 跳过了Bar 的实现,因为Foo 没有指定它要按方法解析顺序委托给下一个类,而是明确指定Base。使用super() 可以解决这个问题:

class Base:
    def test(self):
        print('Base.test')

class Foo(Base):
    def test(self):
        print('Foo.test')
        super().test()

class Bar(Base):
    def test(self):
        print('Bar.test')
        super().test()

class Test(Foo, Bar):
    pass

Test().test()
# Output:
# Foo.test
# Bar.test
# Base.test

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-15
    • 2011-03-04
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    相关资源
    最近更新 更多