Lambda中连接到pyqtSignal的对象的生命周期 [英] Lifetime of object in lambda connected to pyqtSignal

查看:180
本文介绍了Lambda中连接到pyqtSignal的对象的生命周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个对象,并希望在发出PyQt信号时执行其方法之一.并假设我希望它使用未通过信号传递的参数来执行此操作.因此,我创建了一个lambda作为信号的插槽:

Suppose I have an object and want one of its methods to be executed when a PyQt signal is emitted. And suppose I want it to do so with a parameter that is not passed by the signal. So I create a lambda as the signal's slot:

class MyClass(object):
    def __init__(self, model):
        model.model_changed_signal.connect(lambda: self.set_x(model.x(), silent=True))

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

Now, normally with PyQt signals and slots, signal connections don't prevent garbage collection. When a connected slot's object is garbage collected, the slot will no longer be called when the corresponding signal is emitted.

但是,使用lambda时,这如何工作?我没有存储对lambda的引用,但是信号插槽连接确实可以正常工作.因此,lambda不会被垃圾收集.

However, how does this work when using lambdas? I don't store a reference to the lambda, yet the signal-slot connection does keep working. So the lambda is not garbage collected.

如果我现在将MyClass的实例设置为None,则该实例也不会被垃圾收集:发出model_changed_signal仍会成功执行lambda.因此,显然,对MyClass实例的引用保留在某个地方(也许在lambda的上下文中)周围-我不希望这样做.

If I now set the instance of MyClass to None, that instance is not garbage collected either: emitting the model_changed_signal still executes the lambda succesfully. So apparently, a reference to the instance of MyClass is kept around somewhere (maybe in the context of the lambda?) - which I don't want.

为什么会这样?

推荐答案

示例中的lambda构成一个闭包.也就是说,它是一个嵌套函数,引用了其封闭范围内的可用对象.每个创建闭包的函数都会为其每个项目保留一个单元格对象需要保持引用.

The lambda in your example forms a closure. That is, it is a nested function that references objects available in its enclosing scope. Every function that creates a closure keeps a cell object for every item it needs to maintain a reference to.

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

In your example, the lambda creates a closure with references to the local self and model variables inside the scope of the __init__ method. If you keep a reference to the lambda somewhere, you can examine all the cell objects of its closure via its __closure__ attribute. In your example, it would display something like this:

>>> print(func.__closure__)
(<cell at 0x7f99c16c5138: MyModel object at 0x7f99bbbf0948>, <cell at 0x7f99c16c5168: MyClass object at 0x7f99bbb81390>)

如果删除此处显示的对MyModelMyClass对象的所有其他引用,则单元格保留的那些引用仍将保留.因此,在对象清除方面,您应始终明确断开与可能会在相关对象上形成闭合的函数连接的所有信号.

If you deleted all other references to the MyModel and MyClass objects shown here, the ones kept by the cells would still remain. So when it comes to object cleanup, you should always explicitly disconnect all signals connected to functions that may form closures over the relevant objects.

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

Note that when it comes to signal/slot connections, PyQt treats wrapped C++ slots and Python instance methods differently. The reference counts of these types of callable are not increased when they are connected to signals, whereas lambdas, defined functions, partial objects and static methods are. This means that if all other references to the latter types of callable are deleted, any remaining signal connections will keep them alive. Disconnecting the signals will allow such connected callables to be garbage-collected, if necessary.

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

The one exception to the above is class methods. PyQt creates a special wrapper when creating connections to these, so if all other references to them are deleted, and the signal is emitted, an exception will be raised, like this:

TypeError: 'managedbuffer' object is not callable

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

The above should apply to PyQt5 and most versions of PyQt4 (4.3 and greater).

这篇关于Lambda中连接到pyqtSignal的对象的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆