从两个元类派生时 __init__ 中的类型错误
Type error in __init__ when deriving from two metaclasses
我想制作派生自 PyQt5 QtWidget.QWidget
和 abc.ABCMeta
的 class。这两个 classes 都有自己的元 class 作为类型,因此,根据 this page and ,我需要创建自己的元 class,该元 class 派生自元 [=32= QWidget
和 abc.ABCMeta
的 ]es,并明确将其用作我的 class.
的元 class
到目前为止一切顺利,我已经定义了一个 QtAbcMeta
class 并将其用作我的 ConcreteWidget
class 的 metaclass
(见下文) .
import abc
from PyQt5 import QtWidgets, QtCore
class AbstractClass(metaclass=abc.ABCMeta):
def __init__(self, name):
self._name = name
@abc.abstractmethod
def myMethod():
pass
class QtAbcMeta(type(QtWidgets.QWidget), type(AbstractClass)):
pass
class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):
def __init__(self, name, parent=None):
AbstractClass.__init__(self, name)
QtWidgets.QWidget.__init__(self, parent=parent) # This gives a type error.
def myMethod():
print("My widget does something")
def main():
app = QtWidgets.QApplication([])
myWidget = ConcreteWidget('my name', parent=None)
if __name__ == "__main__":
main()
但是,当我尝试调用 QtWidgets.QWidget
方法的 __init__
方法来设置父级时,我得到以下类型错误:
Traceback (most recent call last):
File "main.py", line 36, in <module>
main()
File "main.py", line 33, in main
myWidget = ConcreteWidget('my name', parent=None)
File "main.py", line 24, in __init__
QtWidgets.QWidget.__init__(self, parent=parent) # This gives a type error.
TypeError: __init__() missing 1 required positional argument: 'name'
我不知道这里出了什么问题。 QtWidgets.QWidget.__init__
的签名是否以某种方式改变了?任何帮助将不胜感激。
QT classes 旨在以合作方式在现代 Python 代码中使用 - 这意味着它们在内部使用 Python 的 super()
, 以确保所有 superclasses 中的所有正确方法都使用各自的参数调用。
super()
的创建恰恰是为了避免使用 super-classes __init__
(和其他重写方法)硬编码调用class 个名字,这样你就不用担心调用顺序了。
唯一的问题是每个 class 打算用作 multi-class mixin 必须 "know" 怎么样,提取它使用的命名参数,并使用剩余的参数再次调用 super
。
QT 代码更进一步,检查其他 classes 的所有命名参数是否都已呈现给它,否则会出错。
不仅如此,由于 Qt classes 本身使用 super,这意味着您的 __init__
抽象 class 被调用了两次。它不会对这个简单的代码产生影响,但在更复杂的基础 classes 中可能会出现问题。
所以,只需重写您的 __init__
方法,以 "pythonic" 方式完成:
class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):
def __init__(self, name, parent=None):
super().__init__(name=name, parent=parent)
我想制作派生自 PyQt5 QtWidget.QWidget
和 abc.ABCMeta
的 class。这两个 classes 都有自己的元 class 作为类型,因此,根据 this page and QWidget
和 abc.ABCMeta
的 ]es,并明确将其用作我的 class.
到目前为止一切顺利,我已经定义了一个 QtAbcMeta
class 并将其用作我的 ConcreteWidget
class 的 metaclass
(见下文) .
import abc
from PyQt5 import QtWidgets, QtCore
class AbstractClass(metaclass=abc.ABCMeta):
def __init__(self, name):
self._name = name
@abc.abstractmethod
def myMethod():
pass
class QtAbcMeta(type(QtWidgets.QWidget), type(AbstractClass)):
pass
class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):
def __init__(self, name, parent=None):
AbstractClass.__init__(self, name)
QtWidgets.QWidget.__init__(self, parent=parent) # This gives a type error.
def myMethod():
print("My widget does something")
def main():
app = QtWidgets.QApplication([])
myWidget = ConcreteWidget('my name', parent=None)
if __name__ == "__main__":
main()
但是,当我尝试调用 QtWidgets.QWidget
方法的 __init__
方法来设置父级时,我得到以下类型错误:
Traceback (most recent call last):
File "main.py", line 36, in <module>
main()
File "main.py", line 33, in main
myWidget = ConcreteWidget('my name', parent=None)
File "main.py", line 24, in __init__
QtWidgets.QWidget.__init__(self, parent=parent) # This gives a type error.
TypeError: __init__() missing 1 required positional argument: 'name'
我不知道这里出了什么问题。 QtWidgets.QWidget.__init__
的签名是否以某种方式改变了?任何帮助将不胜感激。
QT classes 旨在以合作方式在现代 Python 代码中使用 - 这意味着它们在内部使用 Python 的 super()
, 以确保所有 superclasses 中的所有正确方法都使用各自的参数调用。
super()
的创建恰恰是为了避免使用 super-classes __init__
(和其他重写方法)硬编码调用class 个名字,这样你就不用担心调用顺序了。
唯一的问题是每个 class 打算用作 multi-class mixin 必须 "know" 怎么样,提取它使用的命名参数,并使用剩余的参数再次调用 super
。
QT 代码更进一步,检查其他 classes 的所有命名参数是否都已呈现给它,否则会出错。
不仅如此,由于 Qt classes 本身使用 super,这意味着您的 __init__
抽象 class 被调用了两次。它不会对这个简单的代码产生影响,但在更复杂的基础 classes 中可能会出现问题。
所以,只需重写您的 __init__
方法,以 "pythonic" 方式完成:
class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):
def __init__(self, name, parent=None):
super().__init__(name=name, parent=parent)