Search code examples
pythondynamicpyqt

why does my code assign boolean to instance self in python


I'm using a dynamic function as getattr() But I don't why my code assign boolean value to self instance and its return follows: AttributeError: 'bool' object has no attribute 'key'

import sys
from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QLabel

class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.ui()

    key = 0
    btns = ["Next", "Back"]

    def ui(self):
        for a in range(0, 2):
            btn = QPushButton(self.btns[a], self)
            btn.move(20, 20 * a + 10)
            btn.clicked.connect(getattr(MyApp, self.btns[a]))

#//////////////////////////////// it's only UI //////////////////////////////////

        self.setWindowTitle('Question')
        self.setGeometry(100, 100, 100, 100)

        self.label1 = QLabel('0', self)
        self.label1.move(20, 60)

        self.show()

#////////////////////////////////////////////////////////////////////////////////

    def Next(self):
        if self.key < 5:
            self.key += 1
        self.label1.setText(self.key)

    def Back(self):
        if 1 <= self.key:
            self.key -= 1
        self.label1.setText(self.key)

#////////////////////////////////////////////////////////////////////////////////

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

Traceback (most recent call last): File "C:\project\pyeditor\QnA.py", line 31, in Next if self.key < 5: AttributeError: 'bool' object has no attribute 'key'

I use a fairly large number of buttons, but I have only taken two buttons as an example to make it easier for you to understand the question. It is generated as a repetitive statement. I also know that if I write button functions one by one, I don't have to worry about the data type of instance values. But then the purpose of factoring is overshadowed. I'd appreciate your help.


Solution

  • The line btn.clicked.connect(getattr(MyApp, self.btns[a])) is the issue. Here you are connecting to the functions MyApp.Next and MyApp.Back instead of the function self.Next and self.Back. The difference is that the class MyApp does not know self since only an instance of MyApp can access it.

    How to fix

    Replace btn.clicked.connect(getattr(MyApp, self.btns[a]))

    with btn.clicked.connect(getattr(self, self.btns[a])).

    Edit

    You also have a small error with setText where you need to convert self.key to a string.