关于Python pyqt批量创建快捷键使用lambda、__dict__时闭包问题引发函数指针错误的问题之解决方案

新人第一次发文章,分享一下做项目时遇到的问题的解决方案QAQ

代码写的不好还请大佬多多包涵!


此段代码是Pyside2/PyQt5.15制作快捷键的一般方法。

class MyWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        # 以上为创建MainWindow的一般方法
        QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+C"), self, self.copying)    
        # 此处以Ctrl+C实现复制快捷键功能为例

首先,在制作项目时发现在代码内设定大量快捷键不但代码累赘,而且不支持后续自定义快捷键,于是考虑使用一个json文件保存键位对应的函数名,在生成快捷键时用__dict__获取对应函数。

{
 "Ctrl+C": "copying",
 "Ctrl+V": "pasting",
 "Ctrl+X": "cutting"
}

(此处的json文本包含了复制、粘贴、剪切三个功能的键位和函数名)

然后按照原思路在刚才的Python代码中MyWindow类中写入以下代码:

with open("shortcut_dict.json", "r", encoding='utf-8') as f:
    self.shortcut_dict = json.loads(f.read())
# 读取json文本,创建快捷键字典

self.shortcut_widget_dict = {}
# 创建一个存放QtWidgets.QShortcut类的字典,以批量生成控件

for key in self.shortcut_dict:
        self.shortcut_widget_dict[self.shortcut_dict[key] + "_short"] = QtWidgets.QShortcut(QtGui.QKeySequence(key), self, lambda: self.__class__.__dict__[self.shortcut_dict[key]](self))
        # 设置快捷键,因为直接写入函数是再调用类内定义的函数,不是当前窗口调用,因此用lambda写入
        # self参数,以免在定义快捷键时就调用函数

这个时候再运行代码,在窗口内使用这些快捷键,就会发现神奇的事情:不管使用哪个快捷键,调用的永远是写在json文件内最后一个快捷键的函数

尝试输出这些lambda匿名函数,发现这些匿名函数在内存中的地址是一样的,它们指向了同一个函数

<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>
<function MyWindow.__init__.<locals>.<lambda> at 0x000001A83335F910>

解决这个问题苦恼了我半天,无意间看到大佬的一篇闭包问题的文章才突然醒悟。

文章链接:Python lambda 与 闭包

这涉及到了python中的一个闭包问题。在定义函数时遍历整个字典,使用相对于定义匿名函数外部的变量时,可以称之为是"惰性"的。没有调用的情况下,所有快捷键对应的匿名函数最终都指向最后一个函数。

解决这个问题,我选择了暂时逃避lambda的麻烦之处,重新写一段用def关键字定义函数的代码。

for key in self.shortcut_dict:
            def execute_short(func=copy.deepcopy(self.__class__.__dict__[self.shortcut_dict[key]])):
                func(self)
                # 使用deepcopy深拷贝函数,而不是一个指针指向函数
            self.shortcut_widget_dict[self.shortcut_dict[key] + "_short"] = QtWidgets.QShortcut(QtGui.QKeySequence(key), self, execute_short)
        # 设置快捷键,调用定义好的函数

至此,批量生成快捷键遇到的难题就解决了。


都看到这里了,大佬们就点个心吧QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值