【发布时间】:2020-12-17 11:03:19
【问题描述】:
我知道标题可能有点混乱,所以让我举个例子。假设您有一个基类Base,它旨在被子类化以创建更复杂的对象。但是你也有可选的功能,你不需要每个子类,所以你把它放在一个二级类OptionalStuffA,它总是打算和基类一起子类化。你是否也应该让那个二级类成为Base的子类?
这当然只有当你有多个OptionalStuff 类并且你想以不同的方式组合它们时才相关,因为否则你不需要子类Base 和OptionalStuffA (并且只需OptionalStuffA 是Base 的子类,所以你只需要子类OptionalStuffA)。我知道如果 Base 不止一次继承自 MRO,这对 MRO 没有影响,但我不确定让所有次要类都继承自 Base 是否有任何缺点。
下面是一个示例场景。我还将QObject 类作为“第三方”令牌类添加,其功能对于辅助类之一的工作是必需的。我在哪里子类化它?下面的例子展示了我到目前为止是如何做到的,但我怀疑这是要走的路。
from PyQt5.QtCore import QObject
class Base:
def __init__(self):
self._basic_stuff = None
def reset(self):
self._basic_stuff = None
class OptionalStuffA:
def __init__(self):
super().__init__()
self._optional_stuff_a = None
def reset(self):
if hasattr(super(), 'reset'):
super().reset()
self._optional_stuff_a = None
def do_stuff_that_only_works_if_my_children_also_inherited_from_Base(self):
self._basic_stuff = not None
class OptionalStuffB:
def __init__(self):
super().__init__()
self._optional_stuff_b = None
def reset(self):
if hasattr(super(), 'reset'):
super().reset()
self._optional_stuff_b = None
def do_stuff_that_only_works_if_my_children_also_inherited_from_QObject(self):
print(self.objectName())
class ClassThatIsActuallyUsed(Base, OptionalStuffA, OptionalStuffB, QObject):
def __init__(self):
super().__init__()
self._unique_stuff = None
def reset(self):
if hasattr(super(), 'reset'):
super().reset()
self._unique_stuff = None
【问题讨论】:
-
对我来说,
if hasattr(super或do_stuff_that表示应该使用继承。 -
这是一个很好的观点。我这样做是因为如果我只调用
super().reset()并到达ClassThatIsActuallyUsed的MRO 的末尾,它会抛出一个错误,因为QObject没有那个方法。 -
子类化
Base和QObject的另一个优点当然是编辑器不会在二级类中标记未解析的引用。 -
像
OptionalStuff这样提供额外功能的类被称为mixin 类,并且继承自object,因此它们可以在各种上下文中使用并避免当类D继承自类C和B(它们都是类A的子类)时可能发生的钻石问题。简而言之,答案是“不”。 -
我明白了,谢谢@Booboo!我在某个时候读过关于钻石问题的文章,但又忘记了。也许这就是我按照我的方式设置课程的原因。我现在正在修改我的代码,并认为必须有一种方法来改进它。我仍然不太喜欢我如何处理整个
if hasattr(super(), 'reset')的事情。有没有更好的方法来做到这一点并确保所有(祖)父类都调用reset?甚至按特定顺序?如果您需要在一个 oder 中调用一种方法而在不同的一种中调用另一种方法怎么办?因为只有一个 MRO,我猜这是不可能的?
标签: python multiple-inheritance method-resolution-order