python - PyQT5 程序中的垃圾收集机制与正常情况有什么区别?(如果这是与 GC 相关的问题)
问题描述
为了了解PyQT5 中元类QObject的对象删除功能,我编写了以下代码:
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_())
上面的代码中有几个明显的事实:
- 该类
Window
有一个非必要属性 ,hook
最初用于绑定到obj1
; obj1
是 的父对象obj2
,obj2
是 的父对象obj3
。如果引用计数中不涉及任何对象,则将快速恢复所有三个对象以激活destroyed
下面的信号接收器并进一步打印此消息。
为了避免 GC,我添加了第 19 行来尝试保留它们,self.hook = obj1
但适得其反。
这是谜题:
如果将第 19 行更改为self.other_attribute_not_schedule = obj1
,则程序不会在 Window UI 实体关闭之前释放这 3 个对象。更清楚地说,您能否告诉我有关使用上述代码删除对象的更多详细信息,以及为什么当我使用另一行时它们不删除?
解决方案
当对象的引用数达到 0 时,垃圾收集会激活。在这种情况下,如果 Qt 允许,python 会尝试删除它。
在您的原始代码中,您首先调用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 会获得对象的所有权(必要时通过重新设置它的父级),例如,将小部件添加到布局然后将布局设置到另一个小部件时。
推荐阅读
- java - 如何将多个字符串值复制到 android 的剪贴板中?
- java - 来自字符串java的随机数计数
- assembly - Doxygen 列出未声明的函数
- mysql - MySQL 中的 YTD 计算来自(SELECT 语句),包括一年中的所有日期
- javascript - 未捕获的 SyntaxError:AJAX 中的输入意外结束
- python - 如何使背景颜色与表单背景相同?
- r - 在 rmarkdown 中循环打印标题、绘图和表格
- angular - 以角度循环单选按钮formControl的正确方法是什么?
- html - 是否可以调整网格的大小并让所有项目都响应新的大小?
- firebase - 快照返回空值----flutter