【问题标题】:Python super() arguments: why not super(obj)?Python super() 参数:为什么不是 super(obj)?
【发布时间】:2013-07-07 06:36:15
【问题描述】:

我试图了解何时以及如何在 Python 中正确使用 super()(2.7.x 或 3.x)

>>> help(super) 上,解释器告诉我如何称呼它:

class super(object)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)

我知道在 Python3.x 中现在可以在类定义中使用 super(),但我不明白为什么 super(obj) 是不可能的。或类定义中的super(self)

我知道这一定是有原因的,但我找不到。对我来说,这些行等同于super(obj.__class__, obj)super(self.__class__, self),它们可以正常工作吗?

我认为即使在 Python 3.x 中输入 super(obj) 也是一个不错的快捷方式。

【问题讨论】:

  • 我本来想说的是,当您在元类上调用 super 时会引起歧义,但后来我意识到这种歧义也存在于 2 参数形式中。现在我不确定了。

标签: python inheritance super


【解决方案1】:

只有在Python 2中才需要双参数形式。原因是self.__class__总是引用继承树中的“叶子”类——也就是对象最具体的类——但是当你调用super你需要告诉它当前正在调用哪个实现,这样它就可以调用继承树中的下一个。

假设你有:

class A(object):
   def foo(self):
      pass

class B(A):
   def foo(self):
      super(self.__class__, self).foo()

class C(B):
   def foo(self):
      super(self.__class__, self).foo()

c = C()

请注意,c.__class__ 始终是 C。现在想想如果你打电话给c.foo()会发生什么。

当你在C的一个方法中调用super(self.__class__, self)时,会像调用super(C, self)一样,意思是“调用C继承的这个方法的版本”。这将调用B.foo,这很好。但是当你从B调用super(self.__class__, self)时,它仍然像调用super(C, self)一样,因为它是相同的self,所以self.__class__仍然是C。结果是B中的调用又会调用B.foo,发生无限递归。

当然,您真正想要的是能够调用super(classThatDefinedTheImplementationThatIsCurrentlyExecuting, self),这实际上是Python 3 super() 所做的。

在 Python 3 中,您只需执行 super().foo() 即可,它会做正确的事情。我不清楚您对 super(self) 作为快捷方式的意思。在 Python 2 中,由于我上面描述的原因,它不起作用。在 Python 3 中,这将是一个“长切”,因为您可以只使用普通的super()

super(type)super(type1, type2) 在 Python 3 中可能仍偶尔需要使用,但对于不寻常的情况,这些用法总是更深奥。

【讨论】:

  • 一位同事曾经将一个调用 super 的方法重构为另一个类中的单独方法,因此代码最终显示为 super(SomeOtherClass, some_obj).method(...) 效果很好,但看起来就像一个错误给任何阅读代码的人。尽管这本可以(并且最终)表达得更好,但super 的两个参数形式在某些边缘情况下仍然有用。
  • 你解释的前4行让我明白了一切。也谢谢你的例子。那是我试图理解的缺失部分。
  • 我们一直提到“深奥”或“边缘”案例。这仅仅是当双重继承要求我们在叶类中覆盖__init__() 时调用两个单独的__init__() 函数吗?
  • @ChrisConlan:所提到的情况是,您使用两种类型而不是类型和实例调用 super 的情况。例如,如果您想调用类方法而不是实例方法。见this question
【解决方案2】:

尝试简短的回答:

self.__class__ 始终是对象实例的实际(“次要”)类——不一定是实现该功能的所需类!

super(self.__class__, self) 替换为super(__class__, self),您就在Python 3 中的方法定义中,因为Python 3 为实现类提供了魔术单元变量__class__

简单地 super() 零参数已经是 Python 3 中 super(__class__, self) 的快捷方式。请参阅 PEP3135

Python 2 既不知道 __class__ 也不知道零参数快捷方式 super()

【讨论】:

  • super() (无参数)有点令人惊讶。 PEP 说它不是关键字,所以它有点不清楚它是如何找到 class 和 self。
  • @user48956 super() 等价于super(__class__, <firstarg>)。无论对super() 的调用在哪里,查看它所定义的方法(直接在类主体中定义的函数),并将__class__ 替换为该类,并将<firstarg> 替换为该方法的第一个参数。跨度>
  • 让我感到困惑(让我谷歌这个问题)是,如果您在 A 类的方法中定义一个调用 super() 的本地函数,但将该本地函数设为另一个 B 类的方法, 那么super() 会将__class__ 解析为A,而不是在执行时动态解析为B。
猜你喜欢
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-07
相关资源
最近更新 更多