Как PyQt понимает, что наш класс наследует от чего-то?

#python #pyqt #pyqt5

#python #pyqt #pyqt5

Вопрос:

Недавно я много копался в PyQt и занимался с ним каким-то персоналом, но внезапно понял, что я не понимаю некоторых базовых сотрудников, которые я делал. Как класс, который наследует, скажем, от QGraphicsView, становится самим QGraphicsView или как он становится QWidget ? Также, насколько я понимаю, когда вы наследуете от чего-то, класс просто получает все методы из класса, который вы наследуете. Вот некоторый код ниже :

 import PyQt5.QtWidgets as QtWidgets
import PyQt5.QtCore as QtCore


class First(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(First, self).__init__(parent)
        print('hello')

class Window(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.window = 'test'
        self.title = 'test'
        self.size = (1000, 650)
        self.create()

    def create(self):
        self.setWindowTitle(self.title)
        self.resize(QtCore.QSize(*self.size))
        self.graphicsWidget = First(self)

        self.mainLayout = QtWidgets.QVBoxLayout( )
        self.mainLayout.addWidget(self.graphicsWidget)
        self.setLayout(self.mainLayout)

if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)
    window = Window( )
    window.setGeometry(500, 300, 800, 600)
    window.show( )
    sys.exit(app.exec_( ))
 

Например, в этом коде я создал класс с именем ‘First’, и он наследуется от QtWidgets.QGraphicsView , а затем я добавляю его в качестве виджета в mainLayout внутри моего класса Window. До сих пор я принимал это как должное и не думал об этом много, но может кто-нибудь объяснить мне, как мой mainLayout.addWidget() , который принимает только QWidgets , понимает, что перед ним QWidget? Потому что, если вы это сделаете print(type(First)) , это не даст <class 'sip.wrappertype'> виджета. Спасибо

Ответ №1:

Наследование направлено на специализацию класса, то есть унаследованный класс должен обладать специфическими характеристиками, присущими классу, от которого он наследует.


QGraphicsView — это QWidget, потому что, если вы выполняете QGraphicsView в диаграмме связей:

 ┌--------------┐   ┌--------------┐ 
|   QObject    |   | QPaintDevice |
└------┬-------┘   └-------┬------┘ 
       |                   |
       └---------┬---------┘
                 |
          ┌------┴------┐
          |   QWidget   |
          └------┬------┘
                 |
          ┌------┴------┐
          |   QFrame    |
          └------┬------┘
                 |
       ┌---------┴---------┐
       |QAbstractScrollArea|
       └---------┬---------┘
                 |
       ┌---------┴---------┐
       |   QGraphicsView   |
       └-------------------┘
 

Из этого следует, что:

  • QGraphicsView — это QAbstractScrollArea .
  • QGraphicsView — это QFrame.
  • QGraphicsView — это QWidget.
  • QGraphicsView — это QObject.
  • QGraphicsView — это QPaintDevice .

Почему print(type(First)) возвращает <class 'sip.wrappertype'> ?

Если документы проверены:

[…]
SIP реализует два супертипа, sip.simplewrapper и sip.wrapper, и мета-тип, sip.wrappertype .

sip.simplewrapper — это супертип sip.wrapper . Супертипом sip.simplewrapper является object .

sip.wrappert — это мета-тип как sip.simplewrapper, так и sip.wrapper . Супертипом sip.wrappert является type .

sip.wrapper поддерживает концепцию владения объектами, описанную в разделе Владение объектами, и по умолчанию является супертипом всех типов, которые генерирует SIP.
[…]

Из этого следует, что sip.wrappertype является метаклассом QObject . И это то, что вы делаете, поскольку type(FooClass) возвращает метакласс FooClass .

Если вы хотите распечатать класс, вы должны использовать объект:

 print(type(self.graphicsWidget))
 

Вывод:

 <class '__main__.First'>
 

Чтобы определить, что объект принадлежит классу (или его родительским классам), вы можете использовать следующие методы, например, если это QWidget:

1.

 if isinstance(obj, QtWidgets.QWidget):
    print("is QWidget")
 

2. Если это QObject

2.1

 if qobject.inherits("QWidget"):
    print("is QWidget")
 

2.2

 if qobject.isWidgetType():
    print("is QWidget")
 

Ответ №2:

First() Экземпляр также является экземпляром QtWidgets.QGraphicsView именно потому, что вы так сказали, т. Е. Вы сделали класс наследуемым от QtWidgets.QGraphicsView . Вы можете проверить это:

 f = First()
isinstance(f, QtWidgets.QGraphicsView)  # True
 

Поскольку QtWidgets.QGraphicsView , в свою очередь, наследуется от QtWidgets.QWidget , также верно следующее:

 isinstance(f, PyQt5.QtWidgets.QWidget)
 

Таким образом, addWidget с радостью принимает экземпляр как QWidget . (Обратите внимание, что addWidget не обязательно выполнять явную проверку типа для экземпляра, который он получает. Код мог работать исключительно из-за того, что экземпляр «крякает, как утка», т.е. у него есть соответствующие методы QWidget).