python - 如何检测 `__init_subclass__` 是否已在子类中被覆盖?
问题描述
通常在 Python 中,可以使用以下技术检测方法是否已在子类中被覆盖:
>>> class Foo:
... def mymethod(self): pass
...
>>> class Bar(Foo): pass
...
>>> Bar.mymethod is Foo.mymethod
True
如果方法 from未在 中被覆盖,则表达式Bar.mymethod is Foo.mymethod
将计算为,但如果方法已在 中覆盖,则计算结果为。此技术适用于从 继承的 dunder 方法以及非 dunder 方法:True
Foo
Bar
False
Bar
object
>>> 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__
解决方案
__init_subclass__
特殊情况下是一个类方法,无论你是否装饰它classmethod
。就像每次通过类实例访问属性时Foo().mymethod
返回一个新method
实例一样,每次通过类本身访问属性时都会Foo.__init_subclass__
生成一个新方法。instance
__subclasshook__
另一方面,必须将其声明为类方法才能正常工作。如果将其定义为简单的函数/实例方法,则不假定它是类方法。
推荐阅读
- python - 在我的网格布局中绘制到许多坐标系,然后使用 seaborn 和 mathplotlib 绘制
- excel - 如何从Excel中的数字中获取第一个有效数字?
- android - 编译 native_app_glue.c 导致库文件无效
- python-3.x - 基于条件的 Pandas 窗口平均值
- java - Java 系统独立的根目录路径
- azure-functions - 在消费计划下的 Azure 函数中使用 ServiceBusTrigger 时会出现延迟吗?
- unix - 我想从删除重复文件的文件中获取唯一数据
- github - 如何在 Visual Studio 上刷新 Github 项目
- python - 如何在保留最后一个索引的同时反转列表?
- c# - 如何让面板出现在镜头前