通常在Python中,可以使用以下技术检测子类是否覆盖了方法:
>>> class Foo:
... def mymethod(self): pass
...
>>> class Bar(Foo): pass
...
>>> Bar.mymethod is Foo.mymethod
True
如果在Bar
中没有覆盖Foo
的方法,则表达式Bar.mymethod is Foo.mymethod
将计算为True
,但是如果在Bar
中覆盖了该方法,则计算结果为False
。此技术适用于从object
继承的dunder方法以及非dunder方法:
>>> Bar.__new__ is Foo.__new__
True
>>> Bar.__eq__ is Foo.__eq__
True
我们可以编写一个函数来形式化这个逻辑,如下所示:
def method_has_been_overridden(superclass, subclass, method_name):
"""
Return `True` if the method with the name `method_name`
has been overridden in the subclass
or an intermediate class in the method resolution order
"""
if not issubclass(subclass, superclass):
raise ValueError(
"This function only makes sense if `subclass` is a subclass of `superclass`"
)
subclass_method = getattr(subclass, method_name)
if not callable(method):
raise ValueError(f"'{subclass.__name__}.{method_name}' is not a method")
return subclass_method is not getattr(superclass, method_name, object())
然而,当涉及到__init_subclass__
和__subclasshook__
这两种方法时,该技术将失败:
>>> class Foo: pass
...
>>> class Bar(Foo): pass
...
>>> Bar.__init_subclass__ is Foo.__init_subclass__
False
>>> Bar.__subclasshook__ is Foo.__subclasshook__
False
而,更让人迷惑的例子如下:
>>> type.__init_subclass__ is type.__init_subclass__
False
我有两个问题:
- 为什么这种技术只会与这些方法失败?(我没有找到任何其他这种技术失败的例子--但如果有,请告诉我!)
- 是否有一种替代技术,可以用来检测在超类中未定义的情况下,子类是否已定义了
__init_subclass__
或__subclasshook__
?
Bar.__init_subclass__.__func__ is Foo.__init_subclass__.__func__
。 - Michael Butscherobject.__init_subclass__
)使用与在Python中编写的classmethods不同的类型,并且C方法的类型不支持__func__
。 - user2357112__init_subclass__
方法的参数绑定 - wim