具有不同init参数的多继承的真正解决方案

时间:2017-06-10 17:13:38

标签: python python-3.x initialization multiple-inheritance

这似乎是一项如此简单的任务,但我现在花费了太多时间,没有解决方案。这是设置:

class A(object):
  def __init__(self, x=0):
    print("A.__init__(x=%d)" % x)

class B(object):
  def __init__(self, y=1):
    print("B.__init__(y=%d)" % y)

class C(A, B):
  def __init__(self, x=2, y=3, z=4):
    super().__init__(x=x, y=y)
    print("C.__init__(z=%d)" % z)

这就是主意,但当然这会导致

TypeError: __init__() got an unexpected keyword argument 'y'

所有其他尝试都以类似方式失败,我可以使用正确的解决方案在互联网上找到 no 资源。唯一的解决方案包括用*args, **kwargs替换所有init参数。这并不适合我的需要。

根据要求,一个真实世界的例子:
(这使用了一种不同的方法,它具有有效的语法,但会产生不需要的结果。)

from PyQt5.QtCore import QObject

class Settings(object):
    def __init__(self, file):
        self.file = file

class SettingsObject(object):
    def __init__(self, settings=None):
        print("Super Init", settings is None)
        self.settings = settings

class MyObject(QObject, SettingsObject):
    def __init__(self, param):
        print("Entering Init")
        QObject.__init__(self)
        SettingsObject.__init__(self, settings=Settings(__file__))
        self.param = param
        print("Leaving Init")

结果:

Entering Init
Super Init True
Super Init False
Leaving Init

我希望第Super Init True行消失。

1 个答案:

答案 0 :(得分:3)

似乎有一些你感到困惑的事情,所以:

  1. 为什么会得到TypeError: __init__() got an unexpected keyword argument 'y'

    因为方法解析顺序(MRO)中__init__的下一个实现是A.__init__,它只接受x。 MRO是C - > A - > B,因此您必须A.__init__接受y(具体或使用**kwargs)并将其传递(再次使用super)至{{1} }。

    B.__init__没有调用每个实现,当然也不能确保它们只获得他们期望的参数,只是调用 next 实施所有参数。

  2. 为什么super会被调用两次,一次使用,一次不使用SettingsObject.__init__

    settings似乎包含对QObject.__init__的调用,super().__init__调用SettingsObject.__init__作为MyObject的MRO中的下一个调用settings。但是,它不会传递任何settings is None参数,因此第一次调用它时,您会看到settings。第二次直接调用它并明确传递settings is not None,所以你看到SettingsObject

  3. 您如何撰写混合课程?

    我认为这是你应该问的问题。 class SettingsObject: # (object) isn't needed in 3.x def __init__(self, *args, settings=None, **kwargs): super().__init__(*args, **kwargs) self.settings = settings 应该是混合类,因此可以正确设计,以便与其混合的层次结构中的其他类协作。在这种情况下:

    QObject.__init__

    从你的例子中可以看出MyObject没有任何必需的参数,但你仍然可以编写混合,以便在可选参数的情况下使用或在其他地方重用。然后class MyObject(SettingsObject, QObject): def __init__(self, param): super().__init__(settings=Settings(file)) self.param = param 实现如下:

    MyObject

    请注意:

    • 混合类在子类化时首先出现,因此MRO是SettingsObject - > QObject - > super().__init__;和
    • 你只需要调用MyObject一次,而不是单独调用每个超类实现。
  4. 作为替代方案,您考虑过构图吗?也许 class MyObject(QObject): def __init__(self, param, settings=None): super().__init__() self.param = param self.settings = settings obj = MyObject('something', Settings(__file__)) 应该接受设置:

    self.settings.method(...)

    现在您调用self.method(...)而不是Installation failed with message Failed to finalize session : Unknown failure (Error: java.lang.SecurityException: Requires android.permission.ASEC_CREATE permission). ,但您没有多重继承引入的复杂性。

相关问题