使用exec()连接多个QPushButton点击信号时程序崩溃问题排查
问题描述
我编写了如下代码:
def top_music_clips(self,clips): try: self.top_20_clips = clips counter = 0 for clip in self.top_20_clips: counter += 1 exec("self.main_self.ui.music_clip_"+str(counter)+".clicked.connect(lambda state,clip_id="+str(clip["id"])+":self.top_clip_clicked(clip_id))") exec("self.main_self.ui.music_clip_"+str(counter)+".setText('"+str(clip["title"])+"')") exec("self.main_self.ui.music_clip_"+str(counter)+".setStyleSheet('QPushButton{font-size:7px;}')") #example for music_clip_1 #self.main_self.ui.music_clip_1.clicked.connect(lambda state,clip_id=self.top_20_clips[0]["id"]:self.top_clip_clicked(clip_id)) except: error_message = traceback.format_exc() self.main_self.open_music_clip_deck_error_window(error_message)
但点击按钮时程序会崩溃,而注释中直接绑定单个按钮的代码可以正常运行,请问问题出在哪里?
问题原因与解决方案
核心问题:exec字符串拼接导致的变量绑定错误
你用exec拼接lambda表达式时,若clip["id"]是字符串类型,拼接后会丢失引号,导致Python将其识别为未定义的变量,点击按钮时触发变量未定义错误,直接崩溃。
比如clip["id"]为"clip_001",拼接后的lambda代码会变成:
lambda state,clip_id=clip_001:self.top_clip_clicked(clip_id)
这里clip_001会被当作变量名而非字符串,运行时找不到该变量,程序崩溃。
另外,exec的使用完全没必要,既增加调试难度,又容易引入字符串拼接错误。
修复代码
import traceback def top_music_clips(self, clips): try: self.top_20_clips = clips # 用enumerate直接生成从1开始的计数器,替代手动维护counter for counter, clip in enumerate(clips, start=1): # 通过getattr直接获取对应按钮控件,避免exec拼接 btn = getattr(self.main_self.ui, f"music_clip_{counter}") # 沿用注释中正确的lambda绑定方式,确保每个按钮绑定当前循环的clip_id btn.clicked.connect(lambda state, clip_id=clip["id"]: self.top_clip_clicked(clip_id)) btn.setText(str(clip["title"])) btn.setStyleSheet("QPushButton{font-size:7px;}") except: error_message = traceback.format_exc() self.main_self.open_music_clip_deck_error_window(error_message)
关键优化点
- 用
getattr直接获取UI控件,彻底抛弃exec,避免字符串拼接的各类错误 - 采用
enumerate自动生成计数器,代码更简洁可靠 - 保留注释中正确的
lambda默认参数绑定逻辑,确保每个按钮绑定的是当前循环的clip["id"]值
内容的提问来源于stack exchange,提问作者Chris P
相关产品推荐
相关产品推荐

