Python 3.10中如何阻止第三方扩展对象的析构函数运行?
阻止Python对象析构函数执行的解决方案
背景
在Python 3.10程序中,使用了第三方扩展模块提供的非纯Python实现的问题对象。由于第三方代码存在bug,该对象的析构函数运行时会导致程序无限期阻塞(等待永远无法获取的互斥锁)。目前修复该阻塞问题的尝试均未成功,但仍在推进。
问题
如何在Python关闭时,有意阻止某个对象的析构函数被调用?例如,test.py中有以下代码:
class MyClass: def __del__(self): print("bye") x = MyClass()
需要确保x的析构函数永远不会运行,“bye”永远不会被打印——无论是程序关闭时还是x超出作用域时?
已尝试方案
- 在优先执行的析构函数中调用
os._exit强制退出,但会导致其他必要的析构函数无法执行,得不偿失。 - 刻意创建包含该对象的引用循环,但无法绕过循环垃圾回收机制。
- 尝试通过
ctypes调用Py_IncRef增加引用计数,未生效:
import ctypes incref = ctypes.pythonapi.Py_IncRef incref.argtypes = [ctypes.py_object] incref.restype = None incref(x)
可行解决方案
1. 直接替换/移除对象的__del__方法
对于纯Python对象,直接将其__del__属性设为None即可:
x.__del__ = None
如果是C扩展实现的对象,可通过ctypes调用Python C API的Py_SetFinalizer函数,将对象的终结器设为NULL:
import ctypes pythonapi = ctypes.PyDLL(None) Py_SetFinalizer = pythonapi.Py_SetFinalizer Py_SetFinalizer.argtypes = [ctypes.py_object, ctypes.c_void_p] Py_SetFinalizer.restype = None # 移除对象的析构函数 Py_SetFinalizer(x, None)
2. 利用垃圾回收机制冻结对象
使用gc模块的freeze()方法,将当前所有对象标记为不可回收,程序退出时不会触发它们的析构函数:
import gc # 先执行一次垃圾回收,清理无用对象 gc.collect() # 冻结现有对象,后续不会被垃圾回收处理 gc.freeze()
注意该操作会影响所有现有对象,适合在程序生命周期后期调用,此时无需再创建需要回收的新对象。
3. 手动保留C层面引用,让对象永不销毁
通过ctypes增加对象的C层面引用计数,再清除所有Python层面的引用,使对象的引用计数始终大于0,垃圾回收器不会触发其析构函数:
import ctypes import gc # 增加C层面引用计数 incref = ctypes.pythonapi.Py_IncRef incref.argtypes = [ctypes.py_object] incref(x) # 清除Python层面的所有引用 del x # 强制触发垃圾回收,此时对象因C层面引用存在不会被销毁 gc.collect()
程序退出时,操作系统会直接回收内存,不会执行Python的析构函数。
内容的提问来源于stack exchange,提问作者Zac B
相关产品推荐
相关产品推荐

