You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5用getattr绑定按钮点击事件导致self为布尔值的报错问题

解决PyQt5动态绑定按钮点击事件时的AttributeError问题

问题描述

在PyQt5中使用getattr()动态绑定按钮点击事件,运行时出现错误AttributeError: 'bool' object has no attribute 'key',不清楚为何self实例被赋值为布尔值。实际场景中有大量按钮,希望通过动态方式绑定而非逐个编写绑定代码,示例代码如下:

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'

错误原因

  1. 方法绑定错误:代码中用getattr(MyApp, self.btns[a])绑定的是类的方法,而非当前实例的方法。Qt的clicked信号默认会传递一个布尔参数(表示按钮是否处于按下状态),信号触发时这个布尔值会被当作第一个参数传入方法,直接覆盖了方法定义中的self参数,导致方法内的self变成布尔值,从而引发属性错误。
  2. 类型不匹配:self.label1.setText(self.key)中,setText()要求传入字符串类型,但直接传入整数self.key会触发类型错误。

解决方法

  1. 绑定实例方法:改用getattr(self, self.btns[a])获取当前实例的方法,同时用lambda包装方法以忽略clicked信号传递的布尔参数,避免参数覆盖self。
  2. 类型转换:将整数self.key转换为字符串后再传入setText()。

修改后的代码

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

class MyApp(QWidget):
    def __init__(self):
        super().__init__()
        self.key = 0  # 改为实例变量,避免多实例共享数据问题
        self.btns = ["Next", "Back"]
        self.ui()

    def ui(self):
        for idx, btn_text in enumerate(self.btns):
            btn = QPushButton(btn_text, self)
            btn.move(20, 20 * idx + 10)
            # 用lambda包装方法,忽略clicked信号的布尔参数
            btn.clicked.connect(lambda _, func=getattr(self, btn_text): func())

        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(str(self.key))  # 转换为字符串类型

    def Back(self):
        if self.key >= 1:
            self.key -= 1
        self.label1.setText(str(self.key))  # 转换为字符串类型

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

额外优化:将key和btns从类变量改为实例变量,避免多个实例之间共享同一数据的问题;使用enumerate遍历按钮文本,代码更简洁易读。

内容的提问来源于stack exchange,提问作者Kim G'bril Jibin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:35:23