为了了解对象删除特性 of metaclass QObject in PyQT5,我编写了以下代码:
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setup_UI()
self.setup_subUI()
self.hook = None
def setup_UI(self):
self.setWindowTitle('MyWindowTitle')
self.resize(600, 400)
def setup_subUI(self):
obj1 = QObject()
obj2 = QObject(obj1)
obj3 = QObject(obj2)
self.hook = obj1 # This is line 19.
obj1.setObjectName('obj1')
obj2.setObjectName('obj2')
obj3.setObjectName('obj3')
obj1.destroyed.connect(lambda obj: print(f'Object {obj.objectName()} has been released'))
obj2.destroyed.connect(lambda obj: print(f'Object {obj.objectName()} has been released'))
obj3.destroyed.connect(lambda obj: print(f'Object {obj.objectName()} has been released'))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())在上面的代码中有几个明显的事实:
obj1;
obj1类具有一个非本质属性hook,它最初用于绑定到Window是obj2的父对象,obj2是obj3的父对象。如果参考计数不涉及任何对象,则将迅速恢复所有三个对象,以激活下面的destroyed信号接收器,并进一步打印此消息。为了避免GC,我添加了第19行,试图保留它们,self.hook = obj1,但是它适得其反。
下面是一个谜题:
如果将第19行更改为self.other_attribute_not_schedule = obj1,程序将不会在窗口UI实体关闭之前释放这3个对象。更清楚的是,,你能告诉我更多关于用上面的代码删除对象的详细信息吗,以及为什么当我使用另一行时它们不被删除?
发布于 2021-07-18 17:03:20
当对象的引用数达到0时,垃圾回收就会激活。在这种情况下,python尝试删除它,如果Qt允许的话。
在您的原始代码中,首先调用setup_subUI,它创建一个引用:
self.hook = obj1然后,在setup_subUI返回之后,执行以下操作:
self.hook = None这将导致将self.hook“覆盖”为对None的引用,因此删除了前面的引用(obj1)。因为这是唯一的参考,它和它的孩子一起被删除了。
然后,再次在setup_subUI中执行以下操作
self.other_attribute_not_schedule = obj1当setup_subUI返回时,下一行将按上面的方式进行计算:
self.hook = None这里的区别是,您没有覆盖self.hook,因为它还不存在,而且obj1也没有被删除,因为它的引用(self.other_attribute_not_schedule)仍然存在。
注有不同类型的引用(例如,将对象添加到持久列表中),它们可能并不总是显式的,特别是对于像Qt这样的复杂模块。
例如,将父对象添加到第一个对象的构造函数将防止删除,即使您执行了self.hook = None。
obj1 = QObject(self)这是因为对象的所有权然后由Qt本身管理。
在很多情况下,Qt获得对象的所有权(必要时通过对其进行修复),例如在向布局中添加小部件时,然后将布局设置为另一个小部件。
https://stackoverflow.com/questions/68431013
复制相似问题