python - 具有不同初始化参数的多重继承的真正解决方案

标签 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'

所有其他尝试都以类似的方式失败,我在互联网上找不到没有具有正确解决方案的资源。唯一的解决方案包括用 *args, **kwargs 替换所有初始化参数。这不太符合我的需求。


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

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. 为什么会出现 TypeError: __init__() got an unexpected keyword argument 'y'

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

    super 不会调用 every 实现,当然也不能确保它们都只得到它们期望的参数,它只是调用 next 使用给定的所有参数实现。

  2. 为什么 SettingsObject.__init__ 被调用两次,一次有 settings,一次没有?

    看起来 QObject.__init__ 包含对 super().__init__ 的调用,它会调用 SettingsObject.__init__ MyObject 的 MRO。但是它不传递任何 settings 参数,因此第一次调用它时您会看到 settings is None。第二次直接调用它并显式传递 settings,因此您会看到 settings is not None

  3. 如何编写混合类?

    我认为这是您真正应该问的问题。 SettingsObject 应该是一个混入类,因此应正确设计以与它混入的层次结构中的其他类协作。在这种情况下:

    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
    

    注意:

    • 混合类在子类化时最先出现,所以MRO是MyObject -> SettingsObject -> QObject;和
    • 您调用 super().__init__ 一次,而不是分别调用每个父类(super class)实现。

作为替代方案,您是否考虑过组合?也许 MyObject 应该采用设置:

 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(...),但你没有那么复杂多重继承介绍。

关于python - 具有不同初始化参数的多重继承的真正解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44475984/

相关文章:

python - PyQt错误 “QProcess: Destroyed while process is still running”

python - 有人可以解释这个 : 0. 2 + 0.1 = 0.30000000000000004 吗?

c++ - 指针的直接初始化

c - 初始化 const struct 并明确哪个字段是哪个

python - 在多索引情况下查找出现最大值的 Dataframe 列

python - 是否有一个特殊值不会在字典中插入键

python - PySpark 数据帧 : Full Outer Join with a condition

python - Pandas tseries Holiday 中的自定义节日庆祝事件

c - 如何区分初始化结构和未初始化结构?

python - 基于多行修改python中的pandas数据框