【发布时间】:2021-07-29 00:10:24
【问题描述】:
我注意到通过这个B.f 实现,调用B.f(B) 引发TypeError:
>>> class A:
... def f(self): print('foo')
...
>>> class B(A):
... def f(self):
... super().f()
... print('bar')
...
>>> B.f(B()) # instance self argument
foo
bar
>>> B.f(B) # non-instance self argument
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
TypeError: f() missing 1 required positional argument: 'self'
但是有了这个B.f 实现,调用B.f(B) 就可以了:
>>> class A:
... def f(self): print('foo')
...
>>> class B(A):
... def f(self):
... if isinstance(self, B): super().f() # bound method call
... else: super().f(self) # function call
... print('bar')
...
>>> B.f(B()) # instance self argument
foo
bar
>>> B.f(B) # non-instance self argument
foo
bar
这是因为super().f(即super(B, self).f)在self 是B 的实例时检索绑定方法 types.MethodType(A.f, self),并检索函数 em> A.f 否则:
>>> super(B, B()).f
<bound method A.f of <__main__.B object at 0x10e6bda90>>
>>> super(B, B).f
<function A.f at 0x10e7d6790>
所以我想知道上面的两个B.f 实现中哪一个是惯用的。换句话说,类设计者是否应该假设类的函数将始终使用作为类实例的self 参数调用(如第一个B.f 实现总是调用super().f 作为绑定方法, 即super().f()),或者他是否也应该处理self 参数不是类* 实例的情况(如第二个B.f 实现,它调用super().f 作为绑定方法,即super().f() , 或作为函数,即super().f(self))?
* 自 Python 3.0 起允许高级用法,这是可能的,如 Guido van Rossum explained:
在 Python 3000 中,未绑定方法的概念已被移除,表达式“A.spam”返回一个普通的函数对象。事实证明,第一个参数必须是 A 的实例的限制对诊断问题几乎没有帮助,并且经常成为高级用法的障碍——有些人称之为“鸭子打字自我”,这似乎是一个合适的名称。
【问题讨论】:
-
正如我在第二个链接的回答中所说:
super()的单参数形式不适用于重要的极端情况,它是在 Python 2 世界中设计的并且已过时。 Guido 同意它应该被视为已弃用。使用这种形式并不习惯。 -
@MartijnPieters 我认为存在混淆。这篇文章实际上根本不是关于
super()的单参数形式(它甚至不是特定于super(),参见下面的my answer)。 Guido指的是鸭子类型self的应用(self理解为类方法的第一个参数,而不是内置函数的第二个参数super()——我认为这是你感到困惑的地方)。 -
@MartijnPieters 所以既然它不是重复的,除非我弄错了,我们可以重新打开这个问题吗?
-
@MartijnPieters 我已经打开了一个related question 关于方法调用可能失败的另一种方式。
标签: python function methods super