既然Python中已经有了垃圾收集器,那么在PyQt/PySide中
deleteLater()
还有必要吗?
这取决于你所说的“必要”是什么意思。
如果(例如)关闭小部件时不小心,应用程序可能会潜在地消耗大量内存。基于 QObject 的类被设计为(可选)在层次结构中链接在一起。当删除顶级对象时,Qt 也会自动删除其所有子对象。但是,当关闭小部件(QObject 的子类)时,只有设置了 Qt.WA_DeleteOnClose 属性(默认情况下通常不会),才会发生自动删除。
为了说明这一点,请尝试重复打开和关闭此演示脚本中的对话框,并观察全局对象列表如何增长:
import sys
from PyQt5 import QtCore, QtWidgets
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.checkbox = QtWidgets.QCheckBox('Delete')
self.button = QtWidgets.QPushButton('Open', self)
self.button.clicked.connect(self.openDialog)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.checkbox)
layout.addWidget(self.button)
def openDialog(self):
widget = QtWidgets.QDialog(self)
if (self.checkbox.isChecked() and
not widget.testAttribute(QtCore.Qt.WA_DeleteOnClose)):
widget.setAttribute(QtCore.Qt.WA_DeleteOnClose)
for child in self.findChildren(QtWidgets.QDialog):
if child is not widget:
child.deleteLater()
label = QtWidgets.QLabel(widget)
button = QtWidgets.QPushButton('Close', widget)
button.clicked.connect(widget.close)
layout = QtWidgets.QVBoxLayout(widget)
layout.addWidget(label)
layout.addWidget(button)
objects = self.findChildren(QtCore.QObject)
label.setText('Objects = %d' % len(objects))
print(objects)
widget.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 100, 50)
window.show()
sys.exit(app.exec_())
使用 PyQt/PySide,对象所有权有两个方面:Python 部分和 Qt 部分。通常,删除对对象的最后一个 Python 引用不足以完全清理,因为 Qt 端仍然可能保留有引用。一般来说,Qt 倾向于
不隐式删除对象。因此,如果您的应用程序创建和删除大量 QObject(或打开和关闭大量 QWidget),如果内存使用量是一个问题,您“可能”需要采取措施显式删除它们。 更新
:只是为了补充上面关于对象所有权的几点。有时,可能会保留对对象的 Python 引用,而 Qt 部分会被删除。发生这种情况时,您将看到如下错误:
运行时错误:底层 C/C++ 对象已被删除
给出了这个警告:通常,Qt 文档会给出一些关于何时可能发生这种情况的提示。例如,
QAbstractItemView.setModel
这告诉您必须保留对该对象的 Python 引用,或者将合适的父对象传递给该对象的构造函数,因为 Qt 并不总是自动重新为其设置父对象。