首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连接到pyqtSignal的lambda中对象的生存期

连接到pyqtSignal的lambda中对象的生存期
EN

Stack Overflow用户
提问于 2017-12-22 12:40:57
回答 1查看 1.3K关注 0票数 6

假设我有一个对象,并希望在发出PyQt信号时执行它的一个方法。假设我希望它用一个不被信号传递的参数来实现。所以我创建了一个lambda作为信号的插槽:

代码语言:javascript
复制
class MyClass(object):
    def __init__(self, model):
        model.model_changed_signal.connect(lambda: self.set_x(model.x(), silent=True))

现在,通常使用PyQt信号和插槽,信号连接不会阻止垃圾收集。当连接槽的对象被垃圾收集时,当发出相应的信号时,将不再调用该插槽。

然而,当使用lambdas时,这是如何工作的呢?我不存储对lambda的引用,但是信号槽连接仍然工作。所以羊肉不是垃圾收集的。

如果我现在将MyClass的实例设置为None,那么该实例也不是垃圾收集的:发出model_changed_signal仍然会成功地执行lambda。因此,很明显,MyClass实例的引用保存在某个地方(可能在lambda的上下文中)--我不想这样做。

这一切为什么要发生?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-22 18:39:50

示例中的lambda形成闭包。也就是说,它是一个嵌套函数,它引用其包围作用域中可用的对象。创建闭包的每个函数都为它需要维护引用的每个项保留一个单元对象

在您的示例中,lambda创建一个闭包,其中引用__init__方法范围内的本地selfmodel变量。如果在某个地方保留了对lambda的引用,则可以通过其__closure__属性检查其闭包的所有单元对象。在您的示例中,它将显示如下所示:

代码语言:javascript
复制
>>> print(func.__closure__)
(<cell at 0x7f99c16c5138: MyModel object at 0x7f99bbbf0948>, <cell at 0x7f99c16c5168: MyClass object at 0x7f99bbb81390>)

如果删除这里显示的对MyModelMyClass对象的所有其他引用,则单元格保存的引用仍将保持不变。因此,当涉及到对象清理时,您应该始终显式地断开连接到可能在相关对象上形成闭包的函数的所有信号。

请注意,当涉及信号/时隙连接时,PyQt对包装的C++插槽和Python实例方法的处理方式不同。这些类型可调用的引用计数是而不是,当它们连接到信号时会增加,而lambdas、定义的函数、部分对象和静态方法则增加。这意味着,如果删除对后一类可调用的所有其他引用,则任何剩余的信号连接都将使它们保持活动状态。如果有必要,断开信号将允许这些连接的可调用项被垃圾收集.

上述方法的一个例外是类方法。PyQt在创建与这些连接的连接时会创建一个特殊的包装器,因此如果删除对它们的所有其他引用并发出信号,将引发异常,如下所示:

代码语言:javascript
复制
TypeError: 'managedbuffer' object is not callable

以上内容应该适用于PyQt5和大多数版本的PyQt4 (4.3及更高版本)。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47941743

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档