PyQt/PySide中连接点击信号时lambda和partial的区别

2023-12-02

当将一组按钮中的多个单击信号连接到带有参数的单个槽函数时,我遇到了信号槽问题。

lambda and functools.partial可以使用如下:

user = "user"
button.clicked.connect(lambda: calluser(name))

from functools import partial
user = "user"
button.clicked.connect(partial(calluser, name))

虽然在某些情况下,它们的表现有所不同。 以下代码显示了一个示例,该示例期望在单击每个按钮时打印每个按钮的文本。 但使用时输出始终为“按钮 3”lambda方法。这partial方法符合我们的预期。

我怎样才能找到他们的差异?

from PyQt5 import QtWidgets

class Program(QtWidgets.QWidget):
    def __init__(self):
        super(Program, self).__init__()
        self.button_1 = QtWidgets.QPushButton('button 1', self)
        self.button_2 = QtWidgets.QPushButton('button 2', self)
        self.button_3 = QtWidgets.QPushButton('button 3', self)
        from functools import partial
        for n in range(3):
            bh = eval("self.button_{}".format(n+1)) 
            # lambda method : always print `button 3`
            # bh.clicked.connect(lambda: self.printtext(n+1))
            bh.clicked.connect(partial(self.printtext, n+1))
        
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.button_1)
        layout.addWidget(self.button_2)
        layout.addWidget(self.button_3)
         
    def printtext(self, n):
        print("button {}".format(n));

if __name__ == '__main__':

    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Program()
    window.show()
    sys.exit(app.exec_())

P.S.

就我个人而言,我同意接受的答案中的 ButtonGroup 方法是解决此类问题的正确优雅的解决方案。

关于这个问题,有一些参考资料:

循环中的 lambda

使用 Qt Signals 传输额外数据


在讨论 lambda/partial 和其他一些问题之间的差异之前,我将简要介绍针对您的代码示例的一些实用修复。

有两个主要问题。第一个是 for 循环中名称绑定的常见问题,如本问题中所述:循环中的 Lambda。第二个是具有默认信号参数的 PyQt 特定问题,如本问题中所述:无法从 Python 循环中创建的按钮发送信号。鉴于此,您的示例可以通过连接信号来修复,如下所示:

bh.clicked.connect(lambda checked, n=n: self.printtext(n+1))

所以这会缓存当前值n在默认参数中,还添加了一个checked停止争论n被信号发出的参数覆盖。

该示例还可以受益于以更惯用的方式重写,从而消除令人讨厌的 eval hack:

layout = QtWidgets.QVBoxLayout(self)
for n in range(1, 4):
    button = QtWidgets.QPushButton(f'button {n}')
    button.clicked.connect(lambda checked, n=n: self.printtext(n))
    layout.addWidget(button)
    setattr(self, f'button{n}', button)

或使用Q按钮组:

self.buttonGroup = QtWidgets.QButtonGroup(self)
layout = QtWidgets.QVBoxLayout(self)
for n in range(1, 4):
    button = QtWidgets.QPushButton(f'button {n}')
    layout.addWidget(button)
    self.buttonGroup.addButton(button, n)
    setattr(self, f'button{n}', button)
self.buttonGroup.buttonClicked[int].connect(self.printtext)

(请注意,也可以通过选择按钮,然后在上下文菜单中选择“分配到按钮组”,在 Qt Designer 中创建按钮组)。


至于lambda和partial的区别问题:主要是前者隐式创建了一个closure覆盖局部变量,而后者显式存储内部传递给它的参数。

Python 中闭包的常见“问题”是循环内定义的函数不会捕获所包含变量的当前值。因此,当稍后调用该函数时,它只能访问最后看到的值。有一个最近在 python-ideas 邮件列表上讨论了更改此行为,但似乎没有得出任何确定的结论。不过,Python 的未来版本可能会消除这个小问题。完全避免了这个问题partial函数,因为它创建了一个可调用对象它将传递给它的参数存储为只读属性。因此,在 a 中使用默认参数的解决方法lambda显式存储变量实际上是使用相同的方法。

这里还有一点值得讨论:使用默认参数连接信号时 PyQt 和 PySide 之间的差异。看来 PySide 将所有插槽视为装饰有插槽装饰器;而 PyQt 则以不同的方式对待未修饰的槽。以下是差异的说明:

def __init__(self):
    ...
    self.button_1.clicked.connect(self.slot1)
    self.button_2.clicked.connect(self.slot2)
    self.button_3.clicked.connect(self.slot3)

def slot1(self, n=1): print(f'slot1: {n=!r}')
def slot2(self, *args, n=1): print(f'slot2: {args=!r}, {n=!r}')
def slot3(self, x, n=1): print(f'slot3: {x=!r}, {n!r}')

依次单击每个按钮后,将产生以下输出:

PyQt5 output:

slot1: n=False
slot2: args=(False,), n=1
slot3: x=False, n=1

PySide2 output:

slot1: n=False
slot2: args=(), n=1
TypeError: slot3() missing 1 required positional argument: 'x'

如果插槽装饰有@QtCore.pyqtSlot(),PyQt5 的输出与上面显示的 PySide2 输出匹配。因此,如果您需要一个对 PyQt 和 PySide 都具有相同作用的 lambda(或任何其他未修饰槽)解决方案,您应该使用:

bh.clicked.connect(lambda *args, n=n: self.printtext(n))

PS:

另请参阅我对以下问题的有关 PySide2/6 进一步差异的回答:

  • PySide-6.6:单击的信号将额外的布尔参数发送到插槽
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PyQt/PySide中连接点击信号时lambda和partial的区别 的相关文章

  • Pandas set_levels,如何避免标签排序?

    我使用时遇到问题set levels多索引 from io import StringIO txt Name Height Age Metres A 1 25 B 95 1 df pd read csv StringIO txt heade
  • 在 Python 中将列表元素作为单独的项目返回

    Stackoverflow 的朋友们大家好 我有一个计算列表的函数 我想单独返回列表的每个元素 如下所示 接收此返回的函数旨在处理未定义数量的参数 def foo my list 1 2 3 4 return 1 2 3 4 列表中的元素数
  • 多输出堆叠回归器

    一次性问题 我正在尝试构建一个多输入堆叠回归器 添加到 sklearn 0 22 据我了解 我必须结合StackingRegressor and MultiOutputRegressor 经过多次尝试 这似乎是正确的顺序 import nu
  • NLTK 2.0分类器批量分类器方法

    当我运行此代码时 它会抛出一个错误 我认为这是由于 NLTK 3 0 中不存在batch classify 方法 我很好奇如何解决旧版本中的某些内容在新版本中消失的此类问题 def accuracy classifier gold resu
  • VSCode Settings.json 丢失

    我正在遵循教程 并尝试将 vscode 指向我为 Scrapy 设置的虚拟工作区 但是当我在 VSCode 中打开设置时 工作区设置 选项卡不在 用户设置 选项卡旁边 我还尝试通过以下方式手动转到文件 APPDATA Code User s
  • 我应该使用 Python 双端队列还是列表作为堆栈? [复制]

    这个问题在这里已经有答案了 我想要一个可以用作堆栈的 Python 对象 使用双端队列还是列表更好 元素数量较少还是数量较多有什么区别 您的情况可能会根据您的应用程序和具体用例而有所不同 但在一般情况下 列表非常适合堆栈 append is
  • 使用主题交换运行多个 Celery 任务

    我正在用 Celery 替换一些自制代码 但很难复制当前的行为 我期望的行为如下 创建新用户时 应向tasks与交换user created路由键 该消息应该触发两个 Celery 任务 即send user activate email
  • 为什么 web2py 在启动时崩溃?

    我正在尝试让 web2py 在 Ubuntu 机器上运行 所有文档似乎都表明要在 nix 系统上运行它 您需要下载源代码并执行以下操作 蟒蛇 web2py py 我抓住了source http www web2py com examples
  • MongoEngine 查询具有以列表中指定的前缀开头的属性的对象的列表

    我需要在 Mongo 数据库中查询具有以列表中任何前缀开头的特定属性的元素 现在我有一段这样的代码 query mymodel terms term in query terms 并且这会匹配在列表 term 上有一个项目的对象 该列表中的
  • Tensorboard SyntaxError:语法无效

    当我尝试制作张量板时 出现语法错误 尽管开源代码我还是无法理解 我尝试搜索张量板的代码 但不清楚 即使我不擅长Python 我这样写路径C Users jh902 Documents logs因为我正在使用 Windows 10 但我不确定
  • 打印包含字符串和其他 2 个变量的变量

    var a 8 var b 3 var c hello my name is var a and var b bye print var c 当我运行程序时 var c 会像这样打印出来 hello my name is 8 and 3 b
  • Python 内置的 super() 是否违反了 DRY?

    显然这是有原因的 但我没有足够的经验来认识到这一点 这是Python中给出的例子docs http docs python org 2 library functions html super class C B def method se
  • Python 3:将字符串转换为变量[重复]

    这个问题在这里已经有答案了 我正在从 txt 文件读取文本 并且需要使用我读取的数据之一作为类实例的变量 class Sports def init self players 0 location name self players pla
  • Java 和 Python 可以在同一个应用程序中共存吗?

    我需要一个 Java 实例直接从 Python 实例数据存储中获取数据 我不知道这是否可能 数据存储是否透明 唯一 或者每个实例 如果它们确实可以共存 都有其单独的数据存储 总结一下 Java 应用程序如何从 Python 应用程序的数据存
  • pandas - 包含时间序列数据的堆积条形图

    我正在尝试使用时间序列数据在 pandas 中创建堆积条形图 DATE TYPE VOL 0 2010 01 01 Heavy 932 612903 1 2010 01 01 Light 370 612903 2 2010 01 01 Me
  • 找到一个数字所属的一组范围

    我有一个 200k 行的数字范围列表 例如开始位置 停止位置 该列表包括除了非重叠的重叠之外的所有类型的重叠 列表看起来像这样 3 5 10 30 15 25 5 15 25 35 我需要找到给定数字所属的范围 并对 100k 个数字重复该
  • 带有 LSTM 的 GridSearchCV/RandomizedSearchCV

    我一直在尝试通过 RandomizedSearchCV 调整 LSTM 的超参数 我的代码如下 X train X train reshape X train shape 0 1 X train shape 1 X test X test
  • 如何以正确的方式为独立的Python应用程序制作setup.py?

    我读过几个类似的主题 但还没有成功 我觉得我错过或误解了一些基本的事情 这就是我失败的原因 我有一个用 python 编写的 应用程序 我想在标准 setup py 的帮助下进行部署 由于功能复杂 它由不同的 python 模块组成 但单独
  • python 对浮点数进行不正确的舍入

    gt gt gt a 0 3135 gt gt gt print 3f a 0 314 gt gt gt a 0 3125 gt gt gt print 3f a 0 312 gt gt gt 我期待 0 313 而不是 0 312 有没有
  • 如何将Python3设置为Mac上的默认Python版本?

    有没有办法将 Python 3 8 3 设置为 macOS Catalina 版本 10 15 2 上的默认 Python 版本 我已经完成的步骤 看看它安装在哪里 ls l usr local bin python 我得到的输出是这样的

随机推荐

  • ShoppingCart 类型的clear() 方法未定义

    我正在通过JSP实现一个购物网站 我有一个名为的 Java 对象ShoppingCart还有一个叫做 Item 在ShoppingCart有一个包含 Item 对象的向量 这个想法是当我打电话给addItem 方法 我使用 cart add
  • 如何在 Python 中将文件读入列表? [复制]

    这个问题在这里已经有答案了 我想提示用户生成一些随机数并将其保存到文件中 他给了我们那部分 我们要做的部分是打开该文件 将数字转换为列表 然后查找平均值 标准差等 而无需使用简单的内置 Python 工具 我尝试过使用open但它给了我无效
  • 更改 Rectangle.Fill 或 Grid.Background 的自定义颜色

    我可以在 xaml 中使用以下内容更改自定义颜色矩形 A125AA 但我不知道在哪里可以找到更改自定义颜色的代码 我只知道颜色代码有 this gridgcolor Background new SolidColorBrush Colors
  • 有反向代理能力的纯Python网络服务器?

    我正在寻找一个基于纯Python的Web服务器也具有反向代理的能力 看一下Twisted 特别是其反向代理资源 Twisted Web 还提供了在反向代理后面设置的各种工具 这是将 Twisted 应用程序与现有站点集成的建议机制
  • mvc3,编辑器模板,css 类,最大长度和大小

    我有一个编辑器模板如下 但 class maxlength 和 size 属性未获取源代码 using System Globalization model DateTime Html TextBox Model null Model Ha
  • GCC 常量变量的弱属性

    我有一个关于 const 变量的弱属性的问题 我用 gcc 编译了以下几个文件 main c include
  • Powershell - 每月计划任务触发器

    我目前正在通过 Powershell 自动创建计划任务 并且我正在使用New ScheduledTaskAction New ScheduledTaskTrigger and Register ScheduledTask命令 现在 我有一些
  • 删除所有已安装的 OpenCV 库

    我正在运行 Kubuntu 11 10 带有 KDE 4 8 在阅读这一切之前 我只想从我的系统中删除 OpenCV 的所有痕迹 这样我就可以重新开始 整个故事 我首先安装了 python opencv 和 libopencv 我认为是 2
  • Javascript 中函数声明中的双冒号?

    今天我发现了这段代码片段 我找不到anything相关解释此语法 真的是JavaScript吗 这是对的吗 如果不是 代码应该是什么样子 这是一个没
  • 更新到 laravel 5.4 后出现会话错误

    从laravel 5 3更新到5 4后 我在vendor中遇到了错误 错误是 Symfony Component Debug Exception FatalThrowableError 调用 var www ostadbank com ve
  • Android BLE扫描模式设置间隔

    我正在编写一个小型测试应用程序来评估蓝牙模块 该应用程序当前正在使用积极的匹配模式和低延迟扫描模式进行扫描 我们控制了蓝牙模块的广告间隔 并正在尝试评估需要多少广告才能触发android中的回调 有谁知道与低延迟 平衡和低功耗扫描模式设置相
  • 使用 Java 在 GUI 编程中混合 awt 和 swing

    我在 SO 上读到混合 awt 和 swing 对于 Java 中的 GUI 编程来说并不是一个好的方法 但我无法找到任何在使用 swing 时不使用某些 awt 组件的示例 例如 即使使用 swing 我遇到的大多数示例也会使用 awt
  • MySQL:如何查询父子关系?

    假设有如下表记录 TABLE foo foo id foo parent id 1 NULL 2 NULL 3 1 4 2 5 1 6 1 7 2 8 1 9 NULL
  • Log4J 2 查找值在加载/呈现之前在配置中使用

    我正在使用 SystemPropertiesLookup 查找来配置我的 Log4J2 配置 系统属性被设置为我的主要方法中的第一行 问题是 当 Log4J 加载配置时 尚未调用 main 方法 因此系统属性尚未填充 这是我的 log4j2
  • 模板类 - 无法解析的外部符号[重复]

    这个问题在这里已经有答案了 我经常收到这个错误 但我不知道为什么 有人可以帮我找到原因吗 编辑 删除代码 将实现 您的方法定义 与类声明一起放入标头中 请参阅这在 C 常见问题解答中 一些编译器支持 export 关键字来按照您的方式执行此
  • 获取上次打开的 MS Word 文档对象

    我有一个从 MS Word 2003 模板 dot 中的 VBA AutoNew 子函数调用的 python 脚本 因此每次从此 Word 模板创建文档时它都会运行 第三方应用程序从此模板创建文档 第三方应用程序如何设置文档存在许多格式问题
  • 多态类中的虚拟析构函数

    我知道只要有一个多态基类 该基类就应该定义一个虚拟析构函数 这样当一个指向派生类对象的基类指针被删除时 它会先调用派生类的析构函数 如果我在这里错了 请纠正我 另外 如果基类析构函数是非虚拟的 则删除指向派生对象的基类指针将是未定义的行为
  • 如何在 .NET MAUI Flyout Shell 应用程序中自定义标题?

    如何缩小标题间距 当我更改汉堡图标时 其图标颜色始终为白色 怎么了 我可以设置标题字体大小和字体系列吗 在 Android 上可以设置contentInsetLeft contentInsetStart contentInsetStartW
  • 如何在 Python 中对文本文件中的数字求和

    我有一个代码依赖于我读取一个文本文件 在有数字的地方打印数字 在有字符串而不是数字的地方打印特定的错误消息 然后将所有数字相加并打印它们的总和 然后只保存编号到新的文本文件 我已经尝试这个问题几个小时了 我得到了下面写的内容 我不知道为什么
  • PyQt/PySide中连接点击信号时lambda和partial的区别

    当将一组按钮中的多个单击信号连接到带有参数的单个槽函数时 我遇到了信号槽问题 lambda and functools partial可以使用如下 user user button clicked connect lambda callus