在PyQt/PySide中是否需要deleteLater() ?

时间:2021-06-29 23:00:48

Since there is already a Garbage Collector in Python, is deleteLater() necessary in PyQt/PySide?

既然在Python中已经有了一个垃圾收集器,那么在PyQt/PySide中需要deleteLater()吗?

2 个解决方案

#1


13  

It depends what you mean by "necessary".

这取决于你所说的“必要”是什么意思。

An application could potentially consume a lot of memory if (for example) care is not taken when closing widgets. The QObject-based classes are designed to be (optionally) linked together in a hierarchy. When a top-level object is deleted, Qt will automatically delete all its child objects as well. However, when closing widgets (which are sub-classes of QObject), automatic deletion will only happen if the Qt.WA_DeleteOnClose attribute is set (which, by default, it usually isn't).

如果(例如)在关闭小部件时不加以注意,应用程序可能会消耗大量内存。基于qobject的类被设计为(可选地)链接在一个层次结构中。当一个*对象被删除时,Qt将自动删除它的所有子对象。但是,当关闭窗口小部件(QObject的子类)时,只有设置了Qt.WA_DeleteOnClose属性(默认情况下通常不是),才会自动删除。

To illustrate, try repeatedly opening and closing the dialog in this demo script, and watch how the global list of objects grows:

为了说明这一点,请尝试在这个演示脚本中反复打开和关闭对话框,并观察全局对象列表是如何增长的:

from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.checkbox = QtGui.QCheckBox('Delete')
        self.button = QtGui.QPushButton('Open', self)
        self.button.clicked.connect(self.openDialog)
        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.checkbox)
        layout.addWidget(self.button)

    def openDialog(self):
        widget = QtGui.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(QtGui.QDialog):
                if child is not widget:
                    child.deleteLater()
        label = QtGui.QLabel(widget)
        button = QtGui.QPushButton('Close', widget)
        button.clicked.connect(widget.close)
        layout = QtGui.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__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 100, 50)
    window.show()
    sys.exit(app.exec_())

With PyQt/PySide, there are two aspects to object ownership: the Python part, and the Qt part. Often, removing the last Python reference to an object won't be enough to fully clean up, because there could still be a reference held on the Qt side.

对于PyQt/PySide,对象所有权有两个方面:Python部分和Qt部分。通常,删除对对象的最后一个Python引用不足以完全清除,因为仍然可以在Qt端保留一个引用。

In general, Qt tends not to implicity delete objects. So if your application creates and removes lots of QObjects (or opens and closes lots of QWidgets), you may need to take steps to delete them explicitly if memory usage is a concern.

一般来说,Qt一般不会删除对象。因此,如果应用程序创建和删除大量qobject(或打开和关闭大量QWidgets),您可能需要采取步骤显式地删除它们,如果需要考虑内存使用情况的话。

UPDATE:

更新:

Just to add to the points above on object ownership. Sometimes, it is possible to hold a Python reference to an object, whilst the Qt part gets deleted. When this happens, you will see an error like this:

再加上上面关于对象所有权的几点。有时,可以保存对对象的Python引用,同时删除Qt部分。当这种情况发生时,您将看到如下错误:

RuntimeError: underlying C/C++ object has been deleted

运行时错误:已删除底层的C/ c++对象

Usually, the Qt documentation will give some hints about when this might happen. For instance, QAbstractItemView.setModel gives this warning:

通常,Qt文档会给出一些提示,说明何时会发生这种情况。例如,QAbstractItemView。setModel给这个警告:

The view does not take ownership of the model unless it is the model's parent object...

视图不拥有模型的所有权,除非它是模型的父对象……

This is telling you that you must either keep a Python reference to the object, or pass a suitable parent object to the object's constructor, because Qt will not always automatically reparent it.

这告诉您,您必须要么保持Python对该对象的引用,要么将合适的父对象传递给对象的构造函数,因为Qt不会总是自动地对其进行重新处理。

#2


0  

One application of deleteLater can be cleaning up of yourself, i.e. scheduling a delete of an QObject (for example in threading) to free resources from within the object itself.

deleteLater的一个应用程序可以清理您自己,例如调度QObject的删除(例如在线程中),从对象本身释放资源。

Here for example someone is using it in connection with the signal thread.finished. It might be restricted to cases with heavy signalling though.

例如,这里有人正在使用它与信号线程连接。不过,它可能被限制在有重型信号的情况下。

#1


13  

It depends what you mean by "necessary".

这取决于你所说的“必要”是什么意思。

An application could potentially consume a lot of memory if (for example) care is not taken when closing widgets. The QObject-based classes are designed to be (optionally) linked together in a hierarchy. When a top-level object is deleted, Qt will automatically delete all its child objects as well. However, when closing widgets (which are sub-classes of QObject), automatic deletion will only happen if the Qt.WA_DeleteOnClose attribute is set (which, by default, it usually isn't).

如果(例如)在关闭小部件时不加以注意,应用程序可能会消耗大量内存。基于qobject的类被设计为(可选地)链接在一个层次结构中。当一个*对象被删除时,Qt将自动删除它的所有子对象。但是,当关闭窗口小部件(QObject的子类)时,只有设置了Qt.WA_DeleteOnClose属性(默认情况下通常不是),才会自动删除。

To illustrate, try repeatedly opening and closing the dialog in this demo script, and watch how the global list of objects grows:

为了说明这一点,请尝试在这个演示脚本中反复打开和关闭对话框,并观察全局对象列表是如何增长的:

from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.checkbox = QtGui.QCheckBox('Delete')
        self.button = QtGui.QPushButton('Open', self)
        self.button.clicked.connect(self.openDialog)
        layout = QtGui.QHBoxLayout(self)
        layout.addWidget(self.checkbox)
        layout.addWidget(self.button)

    def openDialog(self):
        widget = QtGui.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(QtGui.QDialog):
                if child is not widget:
                    child.deleteLater()
        label = QtGui.QLabel(widget)
        button = QtGui.QPushButton('Close', widget)
        button.clicked.connect(widget.close)
        layout = QtGui.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__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 100, 50)
    window.show()
    sys.exit(app.exec_())

With PyQt/PySide, there are two aspects to object ownership: the Python part, and the Qt part. Often, removing the last Python reference to an object won't be enough to fully clean up, because there could still be a reference held on the Qt side.

对于PyQt/PySide,对象所有权有两个方面:Python部分和Qt部分。通常,删除对对象的最后一个Python引用不足以完全清除,因为仍然可以在Qt端保留一个引用。

In general, Qt tends not to implicity delete objects. So if your application creates and removes lots of QObjects (or opens and closes lots of QWidgets), you may need to take steps to delete them explicitly if memory usage is a concern.

一般来说,Qt一般不会删除对象。因此,如果应用程序创建和删除大量qobject(或打开和关闭大量QWidgets),您可能需要采取步骤显式地删除它们,如果需要考虑内存使用情况的话。

UPDATE:

更新:

Just to add to the points above on object ownership. Sometimes, it is possible to hold a Python reference to an object, whilst the Qt part gets deleted. When this happens, you will see an error like this:

再加上上面关于对象所有权的几点。有时,可以保存对对象的Python引用,同时删除Qt部分。当这种情况发生时,您将看到如下错误:

RuntimeError: underlying C/C++ object has been deleted

运行时错误:已删除底层的C/ c++对象

Usually, the Qt documentation will give some hints about when this might happen. For instance, QAbstractItemView.setModel gives this warning:

通常,Qt文档会给出一些提示,说明何时会发生这种情况。例如,QAbstractItemView。setModel给这个警告:

The view does not take ownership of the model unless it is the model's parent object...

视图不拥有模型的所有权,除非它是模型的父对象……

This is telling you that you must either keep a Python reference to the object, or pass a suitable parent object to the object's constructor, because Qt will not always automatically reparent it.

这告诉您,您必须要么保持Python对该对象的引用,要么将合适的父对象传递给对象的构造函数,因为Qt不会总是自动地对其进行重新处理。

#2


0  

One application of deleteLater can be cleaning up of yourself, i.e. scheduling a delete of an QObject (for example in threading) to free resources from within the object itself.

deleteLater的一个应用程序可以清理您自己,例如调度QObject的删除(例如在线程中),从对象本身释放资源。

Here for example someone is using it in connection with the signal thread.finished. It might be restricted to cases with heavy signalling though.

例如,这里有人正在使用它与信号线程连接。不过,它可能被限制在有重型信号的情况下。