父QObject被删除后,子QObject仍可访问的原因是什么?
PyQt5父对象销毁后子对象Python包装仍存在的原因
问题场景
- 创建
QObject对象a - 创建以
a为父对象的QObject对象b - 删除
a
根据Qt官方文档描述:
父对象接管子对象的所有权,即会在析构时自动删除子对象。
但实际运行后出现矛盾现象:
- 变量
b对应的Python对象仍可访问,执行显式垃圾回收也未被清理 - 调用
b.parent()时会抛出RuntimeError,提示C++对象已被销毁
复现代码
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_qobjects()}") # 输出:垃圾回收器追踪的QObjects:[140325587978704, 140325587978848] print(f"a的子对象:{children(a)}") # 输出:a的子对象:[140325587978848] del a print(f"垃圾回收器追踪的QObjects:{tracked_qobjects()}") # 输出:垃圾回收器追踪的QObjects:[140325587978848] gc.collect() # 不保证能清理但不会有危害 print(f"垃圾回收器追踪的QObjects:{tracked_qobjects()}") # 输出:垃圾回收器追踪的QObjects:[140325587978848] # 预期b指向已不存在的对象,但实际仍可访问 print(id(b)) # 输出:140325587978848 print(b) # 输出:<PyQt5.QtCore.QObject object at 0x7fa018d30a60> # 访问父对象触发预期错误 print(b.parent()) # 抛出:RuntimeError: wrapped C/C++ object of type QObject has been deleted
原因解析
这是PyQt的双层对象模型导致的差异:
- 底层C++ Qt对象:完全遵循Qt的父子所有权规则,当父对象
a被销毁时,子对象b的C++实例已经被自动删除。 - 上层Python包装对象:由Python垃圾回收器独立管理,只有当没有任何Python变量引用它时,才会被回收。这里变量
b仍然持有对Python包装对象的引用,所以GC不会清理它。
- 打印
b或获取id(b)仅操作Python包装对象本身,不需要访问底层C++对象,因此不会报错。 - 调用
b.parent()这类方法时,需要访问已销毁的C++对象,因此触发RuntimeError。
内容的提问来源于stack exchange,提问作者bugmenot123
相关产品推荐
相关产品推荐

