python - 从带有和不带有 **kwargs 的类继承

标签 python class inheritance keyword-argument

我正在用 Python 构建一个绘图类,并希望能够执行以下操作。我想要一个使用 PyQt5 的图形窗口,它也继承 self 制作的一些自定义类(例如曲线拟合类)。为了使曲线拟合类能够操作绘图类中保留的数据,它必须具有对绘图类中包含的数据的引用。因此,我选择从 CurveFitting 类继承绘图类。

问题似乎出现在继承 PyQt5 的 GraphicsWindow 类和我的自定义类时,它们接受不同数量的参数。我读过,Python 不能很好地处理使用“ super ”功能继承不同数量参数的类,因此我决定让我的自定义 CurveFitting 类接受 **kwargs,然后为其提供对父级的引用。但是,我随后遇到了一个我不明白的不同错误。下面是我正在尝试做的事情的整理示例

import numpy as np
from pyqtgraph import GraphicsWindow

class ClassA():
    def __init__(self, **kwargs):
        super().__init__()
        self.kwargs = kwargs
        self.parent = self.kwargs['parent']
        self.xdata = self.parent.xdata

    def print_data(self):
        print(self.parent.xdata)
        print(self.parent.ydata)


class classC(GraphicsWindow, ClassA):
    def __init__(self):
        kwargs = {}
        kwargs['parent'] = self
        kargs = kwargs
        self.xdata = np.linspace(0, 100, 101)
        self.ydata = np.linspace(0, 200, 101)

        super().__init__(**kwargs)
        # ClassA.__init__(self, **kwargs)
        # GraphicsWindow.__init__(self)

instC = classC()
instC.print_data()

当我运行上面的代码时,我在“super().__init(**kwargs)”行上得到“RuntimeError: super-class init() of type classC was never called”,其中老实说,我根本不明白,并且尝试谷歌搜索一段时间但无济于事。

此外,我尝试注释掉该行,并取消注释接下来的两行以手动从每个类继承,但这也不起作用。我觉得很奇怪的是,如果我注释掉这两行中的一行,它们都会单独工作,但在一起时就不起作用。例如,如果我用这两行运行它,它会给我一个错误,即 kwargs 没有关键字“parent”,就好像它甚至没有通过 **kwargs 一样。

有没有办法从两个采用不同数量的初始化参数的类继承,就像这样?有没有一种完全不同的方法可以解决这个问题?谢谢。

最佳答案

您的代码的直接问题是 ClassC 继承自 GraphicsWindow 作为其第一个基类,而 ClassA 是第二个基类。当您调用 super 时,只会调用一个 (GraphicsWindow),如果它不是设计用于多重继承(看起来就是这种情况),它可能不会调用super 本身或可能不会传递 ClassA 期望的参数。

只需切换基类的顺序就足以使其工作。 Python 保证基类将以它们在 class 语句中出现的相同相对顺序进行调用(尽管如果稍后发生更多继承,则可能会在 MRO 中在它们之间插入其他类)。由于 ClassA.__init__ 确实调用了 super,它应该工作得更好!

尽管所有涉及的类都被设计为可以使用多重继承,但让 __init__ 方法与多重继承一起使用可能会很棘手。这就是为什么经常避免使用位置参数,因为它们的顺序可能会变得非常困惑(因为子类只能在其父类的位置参数之前添加位置参数,除非它们想要重复所有名称)。使用关键字参数绝对是更好的方法。

但是您拥有的代码使处理关键字参数变得比应有的更加复杂。您不需要显式创建字典来使用 **kwargs 语法传递,也不需要从使用 **kwargs 接受的字典中提取关键字值争论。通常每个函数都应该命名它所采用的参数,并且仅对未知参数使用 **kwargs(MRO 中的其他类可能需要)。看起来像这样:

class Base1:
    def __init__(self, *, arg1, arg2, arg3, **kwargs):  # the * means the other args are kw-only
        super().__init__(**kwargs)                      # always pass on all unknown arguments
        ...                                             # use the named args here (not kwargs)

class Base2:
    def __init__(self, *, arg4, arg5, arg6, **kwargs):
        super().__init__(**kwargs)
        ...

class Derived(Base1, Base2):
    def __init__(self, *, arg2, arg7, **kwargs):         # child can accept args used by parents
        super().__init__(arg2=arg2+1, arg6=3, **kwargs)  # it can then modify or create from
        ...                                              # scratch args to pass to its parents

obj = Derived(arg1=1, arg2=2, arg3=3, arg4=4, arg5=5, arg7=7) # note, we've skipped arg6
                                                              # and Base1 will get 3 for arg2

但我也会认真考虑继承在您的情况下是否有意义。将两个基类之一封装在子类中而不是继承它可能更有意义。也就是说,您只能从 ClassAGraphicsWindow 之一继承,并将另一个实例存储在 ClassC 的每个实例中。 (您甚至可以从两个基类都继承,然后封装它们。)封装通常比继承更容易推理和正确实现。

关于python - 从带有和不带有 **kwargs 的类继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51164663/

相关文章:

python - 如何获取列表框中选定项目的数量?

Java 泛化类引用

c# - 虚函数只能在 C++ 中重写吗?

c++ - 相同成员函数的公有和私有(private)访问

c# - C# 中的方法可以覆盖另一个方法并同时是虚拟的吗?

python - Perl 的 HTML::Form::ForceValue 在 Python 中等效

python - Python音频功能无法正常工作

python - 执行类似 ./program_name 的程序

java - 父类(super class)---包与类

Python:递归方法回滚变化?