使用Lambda传递变量至PyQt5函数时触发NameError: name 'self' is not defined错误的问题排查求助
问题根源与解决方案
我来帮你拆解这个报错的原因,以及给出彻底解决的方案:
首先,你遇到的NameError: name 'self' is not defined,核心问题出在你滥用了exec()和eval()来创建UI组件和执行代码,这两个函数的作用域处理很容易出问题,再加上lambda的延迟绑定陷阱,才导致了这个错误。
为什么会触发这个错误?
在类的方法内部,exec()默认使用的是局部作用域,但直接用它执行包含self的字符串代码时,解释器经常无法正确绑定self到当前实例,就会抛出找不到self的错误。而且exec()和eval()本身就很难调试,还会带来安全风险,完全不适合用来做动态UI创建这种场景。
另外,你写的exec("self.pushButton.clicked.connect(lambda: self.show_Id(nameInfo"+'(str(count))'+"))")还有个隐藏坑:lambda是延迟绑定变量的,所有按钮的点击事件最终都会用循环结束时count的最终值,而不是每个按钮对应的那个值,就算self的问题解决了,点击按钮也会传错参数。
正确的解决方式:
完全丢掉exec()和eval(),用正常的Python代码来动态创建按钮,同时解决lambda的延迟绑定问题。修改后的show_items方法如下:
def show_items (self): cu.execute("SELECT * FROM notes ") all_notes = cu.fetchall() height = 0 push_style = "background-color: rgb(249, 167, 183);\nborder : none;" for idx, note in enumerate(all_notes, start=1): name_info = str(note[0]) # 直接创建按钮,不需要用exec/eval折腾 push_button = QtWidgets.QPushButton(self.infoFrame) push_button.setGeometry(QtCore.QRect(10, height, 655, 110)) push_button.setMinimumSize(QtCore.QSize(655, 110)) push_button.setMaximumSize(QtCore.QSize(200, 110)) push_button.setStyleSheet(push_style) push_button.setText(name_info) # 用默认参数捕获当前的name_info,解决lambda延迟绑定的问题 push_button.clicked.connect(lambda _, name=name_info: self.show_Id(name)) push_button.setObjectName(f"pushButton_{idx}") height += 130 main_height = height + 120 self.infoFrame.setMinimumHeight(main_height)
几个关键的改进点:
- 移除
exec()和eval():直接通过代码实例化QPushButton,作用域清晰,不会出现self找不到的问题,代码也更容易读和调试。 - 解决lambda延迟绑定:给lambda加一个默认参数
name=name_info,这样每个lambda都会捕获当前循环里的name_info值,而不是最后一次循环的结果。 - 简化变量逻辑:把动态命名的
nameInfoX换成普通局部变量name_info,用enumerate来处理计数,代码更简洁。 - 优化变量名:把
all改成all_notes,让变量含义更明确。
这样修改后,不仅能解决NameError的问题,还能保证每个按钮点击时都能传递正确的参数到show_Id方法里。
内容的提问来源于stack exchange,提问作者amirali rostami
相关产品推荐
相关产品推荐

