如何根据 Python 中的基础 class 方法是否存在有条件地覆盖它们?
How do I override base class methods in Python conditionally on whether they exist?
我有 classes BasicEvidenceTarget
和 SchedulableSoma
。有时我继承自SchedulableSoma, BasicEvidenceTarget
,有时我单独继承自SchedulableSoma
。当我从 SchedulableSoma, BasicEvidenceTarget
继承时,我希望 SchedulableSoma
覆盖方法 BasicEvidenceTarget.inject_basic_evidence
。这样做的好方法是什么?
覆盖看起来像这样:
class SchedulableSoma(SchedulableCluster, Soma):
# This is a possible overload of this method in BasicEvidenceTarget.
def inject_basic_evidence(self, *args, **kwargs):
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
现在我是无条件重写基础class方法,所以如果它不存在,就会有一点方法污染:如果调用重写,调用super会失败。有条件地生成覆盖会更好。
我觉得有一个 __prepare_subclass__
魔法可能会奏效,但我不确定具体该怎么做。
我认为这个问题可以通过不同的继承模式来解决。使用你的想法:
class YourClass(SchedulableSoma, BasicEvidenceTarget):
def inject_basic_evidence(self, *args, **kwargs):
if isinstance(self, BasicEvidenceTarget):
BasicEvidenceTarget.inject_basic_evidence(self, *args, **kwargs)
else:
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
或者
class YourClass(SchedulableSoma, BasicEvidenceTarget):
if issubclass(YourClass, BasicEvidenceTarget):
def inject_basic_evidence(self, *args, **kwargs):
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
如果没有 funcy metaclass 业务,您在 class 定义时间无法完成您的尝试。这可以在实例创建时使用以下代码完成:
class SchedulableSoma(SchedulableCluster, Soma):
def __init__(self,*args,**kwargs):
super().__init__(self,*args,**kwargs)
if hasattr(self,"inject_basic_evidence"):
def inject_basic_evidence(*args, **kwargs):
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
self.inject_basic_evidence = inject_basic_evidence
注意:如果 SchedulableSoma
的子 class 覆盖 inject_basic_evidence
,这将不起作用
您可以在定义继承它的 class 时使用工厂函数生成适当的 class。这只是一个草图:
def makeSubclass(otherclass):
class MixedClass(otherclass):
if otherClass == BasicEvidenceTarget:
def inject_basic_evidence(...):
# ...
elif otherClass == WhateverOtherClass:
def some_other_method(...):
# ...
那么你会做:
class SchedulableSoma(makeSubclass(BasicEvidenceTarget)):
# ...
另一种可能性是简单地定义 SchedulableSoma 中的所有方法,但在其中包含检查,如果当前实例未从适当的 class 继承,则会引发异常。类似于:
class SchedulableSoma(object):
def inject_basic_evidence(self, *args, **kwargs):
if not isinstance(self, BasicEvidenceTarget):
raise TypeError("Cannot call inject_basic_evidence unless you inherit from BasicEvidenceTarget")
def some_other_method(self, *args, **kwargs):
if not isinstance(self, SomeOtherClass):
raise TypeError("Cannot call some_other_method unless you inherit from SomeOtherClass")
# similar checks for other classes
这样,对 inject_basic_evidence
的调用将立即失败并显示更具体的错误消息,而不是对 super
调用失败并显示有关 "super object has no attribute" 或喜欢。
最终您可能想考虑是否有更稳健的方式来构建您的 class 层次结构。 classes 根据某些其他 classes 是否也出现在继承层次结构中来改变自己的行为有点神奇,这可能会使用户感到困惑或导致 [=26= 之间无法预料的交互]在路上。
我有 classes BasicEvidenceTarget
和 SchedulableSoma
。有时我继承自SchedulableSoma, BasicEvidenceTarget
,有时我单独继承自SchedulableSoma
。当我从 SchedulableSoma, BasicEvidenceTarget
继承时,我希望 SchedulableSoma
覆盖方法 BasicEvidenceTarget.inject_basic_evidence
。这样做的好方法是什么?
覆盖看起来像这样:
class SchedulableSoma(SchedulableCluster, Soma):
# This is a possible overload of this method in BasicEvidenceTarget.
def inject_basic_evidence(self, *args, **kwargs):
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
现在我是无条件重写基础class方法,所以如果它不存在,就会有一点方法污染:如果调用重写,调用super会失败。有条件地生成覆盖会更好。
我觉得有一个 __prepare_subclass__
魔法可能会奏效,但我不确定具体该怎么做。
我认为这个问题可以通过不同的继承模式来解决。使用你的想法:
class YourClass(SchedulableSoma, BasicEvidenceTarget):
def inject_basic_evidence(self, *args, **kwargs):
if isinstance(self, BasicEvidenceTarget):
BasicEvidenceTarget.inject_basic_evidence(self, *args, **kwargs)
else:
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
或者
class YourClass(SchedulableSoma, BasicEvidenceTarget):
if issubclass(YourClass, BasicEvidenceTarget):
def inject_basic_evidence(self, *args, **kwargs):
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
如果没有 funcy metaclass 业务,您在 class 定义时间无法完成您的尝试。这可以在实例创建时使用以下代码完成:
class SchedulableSoma(SchedulableCluster, Soma):
def __init__(self,*args,**kwargs):
super().__init__(self,*args,**kwargs)
if hasattr(self,"inject_basic_evidence"):
def inject_basic_evidence(*args, **kwargs):
super().inject_basic_evidence(*args, **kwargs)
self.ask_for_reschedule()
self.inject_basic_evidence = inject_basic_evidence
注意:如果 SchedulableSoma
的子 class 覆盖 inject_basic_evidence
您可以在定义继承它的 class 时使用工厂函数生成适当的 class。这只是一个草图:
def makeSubclass(otherclass):
class MixedClass(otherclass):
if otherClass == BasicEvidenceTarget:
def inject_basic_evidence(...):
# ...
elif otherClass == WhateverOtherClass:
def some_other_method(...):
# ...
那么你会做:
class SchedulableSoma(makeSubclass(BasicEvidenceTarget)):
# ...
另一种可能性是简单地定义 SchedulableSoma 中的所有方法,但在其中包含检查,如果当前实例未从适当的 class 继承,则会引发异常。类似于:
class SchedulableSoma(object):
def inject_basic_evidence(self, *args, **kwargs):
if not isinstance(self, BasicEvidenceTarget):
raise TypeError("Cannot call inject_basic_evidence unless you inherit from BasicEvidenceTarget")
def some_other_method(self, *args, **kwargs):
if not isinstance(self, SomeOtherClass):
raise TypeError("Cannot call some_other_method unless you inherit from SomeOtherClass")
# similar checks for other classes
这样,对 inject_basic_evidence
的调用将立即失败并显示更具体的错误消息,而不是对 super
调用失败并显示有关 "super object has no attribute" 或喜欢。
最终您可能想考虑是否有更稳健的方式来构建您的 class 层次结构。 classes 根据某些其他 classes 是否也出现在继承层次结构中来改变自己的行为有点神奇,这可能会使用户感到困惑或导致 [=26= 之间无法预料的交互]在路上。