无法在__del__()中引用导入的模块

6 投票
2 回答
1101 浏览
提问于 2025-04-17 08:46

我在使用一个对象的 __del__() 方法来取消它对某个事件的订阅(这个事件系统的工作方式类似于这个):

import my_enviroment
class MyClass():
    def __del__(self):
        my_environment.events.my_event -= self.event_handler_func

奇怪的是,在程序运行结束时,我收到了以下错误:

Exception AttributeError: "'NoneType' object has no attribute 'events'" in <bound method MyClass.__del__ of <myclass.MyClass instance at 0x04C54580>> ignored

这怎么可能呢?! my_environment 是我导入的一个模块,怎么会变成 None 呢?(events 是它里面的一个全局对象,包含像 my_event 这样的事件钩子)

2 个回答

4

如果你查看Python的文档,就会发现当程序结束时,所有对象都会被销毁,这个过程就像机器拆解一样。这意味着你依赖的一些东西,比如全局变量,可能在这个时候已经不复存在了。

所以,你需要做的是确保那些需要调用__del__的方法的对象在程序结束之前就被销毁。更好的办法是把这些对象做成上下文管理器,也就是有__enter____exit__方法的对象,然后在with语句中使用它们。或者,你也可以把__del__里的代码放在try-except块中,这样即使出现异常也不会影响程序结束,前提是这些代码在程序结束时不是特别重要。

7

根据Python文档关于__del__的说明:

[...] __del__()方法中引用的其他全局变量可能已经被删除,或者正在被清理(比如导入机制正在关闭)。因此,__del__()方法应该尽量只做维持外部状态所需的最小操作。

换句话说,当你的对象调用__del__方法时,my_enviroment可能已经被Python“删除”了,所以它可能会变成None……

撰写回答