Ошибка ввода в __init__ при выводе из двух метаклассов - PullRequest
0 голосов
/ 22 октября 2018

Я хотел бы создать класс, производный от PyQt5 QtWidget.QWidget и abc.ABCMeta.Оба этих класса имеют свой собственный метакласс как тип, поэтому в соответствии с этой страницей и этим SO вопросом мне нужно создать свой собственный метакласс, производный от метаклассов QWidget и abc.ABCMeta, и явно использовать это как метакласс для моего класса.

Пока все хорошо, я определил класс QtAbcMeta и использовал его как metaclass для своего класса ConcreteWidget (увидеть ниже).

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()

Однако, когда я пытаюсь вызвать метод __init__ метода QtWidgets.QWidget, чтобы установить родителя, я получаю следующую ошибку TypeError:

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__?Любая помощь будет оценена.

1 Ответ

0 голосов
/ 13 ноября 2018

Классы QT предназначены для совместного использования в современном коде Python - и это означает, что они внутренне используют super() Python, чтобы гарантировать, что все надлежащие методы во всех суперклассах вызываются с соответствующими параметрами.

Создание super() произошло именно для того, чтобы избежать необходимости жестко кодировать вызовы суперклассов __init__ (и других переопределенных методов) с именами суперклассов, итак что вам не нужно беспокоиться о порядке вызова.

Единственное, что каждый класс, который предназначен для использования в качестве мультиклассового миксина, должен «знать», как это происходит, извлечьон использует именованные параметры и снова вызывает super с оставшимися параметрами.Код QT идет еще дальше и проверяет, представлены ли ему все именованные параметры для других классов, в противном случае он выдает ошибки.

Более того, поскольку сами классы Qt используют super, это означает, что ваш __init__ в абстрактном классе вызывается дважды.В этом простом коде ничего не изменится, но может возникнуть проблема в более сложных базовых классах.

Итак, просто перепишите ваш __init__ метод, чтобы сделать это «питоническим» способом:

class ConcreteWidget(QtWidgets.QWidget, AbstractClass, metaclass=QtAbcMeta):

    def __init__(self, name, parent=None):
        super().__init__(name=name, parent=parent)
...