为什么子QObject没有被删除?

问题描述 投票:0回答:1

为了了解有关 PyQt 的更多信息,我编写了一个小脚本:

  • 创建一个
    QObject
    a
  • 创建一个
    QObject
    b
    ,并将
    a
    作为其父级
  • 删除
    a

此时,我希望名称

b
所指向的对象也已被删除。 Qt 的文档(不是 PyQt!)

父级获得该对象的所有权;即,它会自动 在其析构函数中删除其子级。

但是

b
仍然指向一个现有的对象。
我还尝试了显式垃圾收集,没有任何改变。
正如预期的那样,尝试通过
a
b
方法访问
parent()
会失败。

为什么删除“拥有”

QObject
b
时,
a
引用的
b
没有被删除?

我已将打印输出添加为以下注释:

import gc

from PyQt5.QtCore import QObject


def tracked_qobjects():
    return [id(o) for o in gc.get_objects() if isinstance(o, QObject)]


def children(qobject: QObject):
    return [id(c) for c in qobject.findChildren(QObject)]


a = QObject()
b = QObject(parent=a)
print(f"QObjects tracked by gc: {tracked_qobjects()}")
# QObjects tracked by gc: [140325587978704, 140325587978848]
print(f"Children of a: {children(a)}")
# Children of a: [140325587978848]

del a
print(f"QObjects tracked by gc: {tracked_qobjects()}")
# QObjects tracked by gc: [140325587978848]

gc.collect()  # not guaranteed to clean up but should not hurt
print(f"QObjects tracked by gc: {tracked_qobjects()}")
# QObjects tracked by gc: [140325587978848]

# Since https://doc.qt.io/qt-5/qobject.html#details says:
# "The parent takes ownership of the object; i.e., it will automatically delete
# its children in its destructor."
# I expect that b now points to a non-existent object.
# But no, this still works! Maybe because we are in PyQt5 and
# not a C++ application?
print(id(b))
# 140325587978848
print(b)
# <PyQt5.QtCore.QObject object at 0x7fa018d30a60>

# The parent is truly gone though and trying to access it from its child raises the "wanted" RuntimeError
print(b.parent())
# RuntimeError: wrapped C/C++ object of type QObject has been deleted
python qt pyqt pyqt5 ownership
1个回答
0
投票

这是一个转移注意力的事情。 Python仍然可以提供名称

b
所指向的内存地址(id)以及预期存在的对象的类型,但实际的对象已经被销毁了:

from PyQt5.QtCore import QObject


def children(qobject: QObject):
    return [id(c) for c in qobject.findChildren(QObject)]


def on_destroyed():
    print("x_x")


a = QObject()
b = QObject(parent=a)
b.destroyed.connect(on_destroyed)
print(f"Children of a: {children(a)}")

print("Deleting a...")
del a
print("a has been deleted.")

# Since https://doc.qt.io/qt-5/qobject.html#details says:
# "The parent takes ownership of the object; i.e., it will automatically delete its children in its destructor."
# b now points to a non-existent object.

# Python still knows its memory address and type:
print(id(b))
print(b)

# But trying to do anything with it will fail with the RuntimeError:
print(b.objectName())

结果

Children of a: [140051377982048]
Deleting a...
x_x
a has been deleted.
140051377982048
<PyQt5.QtCore.QObject object at 0x7f6040a28a60>
Traceback (most recent call last):
  File "/.../parental_issues.py", line 30, in <module>
    print(b.objectName())  # RuntimeError: wrapped C/C++ object of type QObject has been deleted
          ^^^^^^^^^^^^^^
RuntimeError: wrapped C/C++ object of type QObject has been deleted
© www.soinside.com 2019 - 2024. All rights reserved.