Python 从包含或不包含**KWARG的类继承
我正在用Python构建一个plotting类,并希望完成以下工作。我想要一个使用PyQt5的图形窗口,它也继承了我创建的一些自定义类(例如曲线拟合类)。为了使曲线拟合类能够处理plotting类中存在的数据,它必须具有对plotting类中包含的数据的引用。因此,我选择了plotting类从CurveFitting类继承 问题似乎出现在继承PyQt5的GraphicsWindow类和我的自定义类时,它们接受不同数量的参数。我已经读到Python不能很好地处理使用“super”功能继承不同数量参数的类,因此我决定让我的自定义CurveFitting类接受**kwargs,这将给它一个对父类的引用。然而,我随后遇到了另一个我不理解的错误。下面是我正在尝试做的一个整理好的例子Python 从包含或不包含**KWARG的类继承,python,class,inheritance,keyword-argument,Python,Class,Inheritance,Keyword Argument,我正在用Python构建一个plotting类,并希望完成以下工作。我想要一个使用PyQt5的图形窗口,它也继承了我创建的一些自定义类(例如曲线拟合类)。为了使曲线拟合类能够处理plotting类中存在的数据,它必须具有对plotting类中包含的数据的引用。因此,我选择了plotting类从CurveFitting类继承 问题似乎出现在继承PyQt5的GraphicsWindow类和我的自定义类时,它们接受不同数量的参数。我已经读到Python不能很好地处理使用“super”功能继承不同数量参
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()。uu init(**kwargs)”行上得到了“RuntimeError:classC类型的super classinit()从未被调用”,我真的一点也不懂,并且已经尝试过谷歌搜索了一段时间,但没有结果
此外,我还尝试注释掉这一行,并取消注释接下来的两行以手动从每个类继承,但这也不起作用。我觉得很奇怪的是,如果我把这两行中的一行注释掉,它们都是单独工作的,但在一起却不工作。例如,如果我用两行运行它,它会给我一个错误,kwargs没有关键字“parent”,好像它甚至没有通过**kwargs
有没有一种方法可以从采用不同数量的初始化参数的两个类中继承?我有没有完全不同的方法来解决这个问题?谢谢 代码的直接问题是
ClassC
继承自GraphicsWindow
作为第一个基类,而ClassA
是第二个基类。当您调用super
时,只调用一个(GraphicsWindow
),如果它不是设计用于多重继承的(似乎是这样),它可能不会调用super
本身,也可能不会传递ClassA
所期望的参数
只要切换基类的顺序就足以使它工作。Python保证基类的调用顺序与它们在中的class
语句中出现的顺序相同(不过如果以后发生更多继承,则可以在MRO中在它们之间插入其他类)。既然ClassA.\uuuu init\uuuu
确实调用了super
,它应该工作得更好
但是,要使\uuuu init\uuuu
方法与多重继承一起工作可能很棘手,即使所有涉及的类都设计为与多重继承一起工作。这就是为什么经常避免使用位置参数,因为它们的顺序可能会变得非常混乱(因为子类只能在其父类的位置参数之前添加位置参数,除非它们想重复所有名称)。使用关键字参数绝对是一种更好的方法
但是您的代码使得处理关键字参数比它应该的要复杂一些。您不需要显式地创建字典来传递**kwargs
语法,也不需要从使用**kwargs
参数接受的dict中提取关键字值。通常每个函数都应该命名它所使用的参数,并且只对未知参数使用**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
但我也会认真考虑,在你的情况下,继承是否有意义。将两个基类中的一个封装在子类中可能更有意义,而不是从子类继承。也就是说,您将只从
ClassA
或GraphicsWindow
中的一个继承,并在ClassC
的每个实例中存储另一个实例。(您甚至可以从两个基类中都不继承,并将它们都封装起来。)封装通常比继承更容易推理和正确处理。关于代码的一些注释(因为它已经被简化了,我很欣赏):在ClassA
中super()的目的是什么?c类中的kargs=kwargs
的目的是什么?您是否尝试过在classC
中交换基类的顺序(以防GraphicsWindow
处理varargs做得很好)?另外,可能值得回顾一下(我误解了您的代码,现在您使用ClassA
a几乎是一个混音,这应该可以回答第一个问题)。谢谢,我认为我在这里学到的最好的东西是,当你不必依赖继承时,不必依赖继承。通过在plotting类中创建GraphicsWindow的实例,我能够实现相同的功能,然后绕过了所有其他问题。我可以通过切换GraphicsWindow和我的自定义类的顺序来运行这个类,但是进一步的复杂情况开始发生,我不理解。