python ImportError in __del__ ,如何解决这个问题?

iou*_*vxz 1 python exception

class foo:
    def __del__(self):
        import os

p = foo()
Run Code Online (Sandbox Code Playgroud)

这导致了导入错误

Exception ignored in: <function foo.__del__ at 0x000001DF9986DE50>
Traceback (most recent call last):
  File "C:\Users\chen\PycharmProjects\pythonProject\main.py", line 3, in __del__
ImportError: sys.meta_path is None, Python is likely shutting down
Run Code Online (Sandbox Code Playgroud)

我只是用这个例子来演示问题所在,我需要在del中导入库,这可以实现吗?

Sha*_*ger 5

根据__del__文档

警告 - 由于__del__()调用方法的情况不稳定,执行期间发生的异常将被忽略,而是打印警告sys.stderr。尤其:

  • __del__()可以在执行任意代码时调用,包括从任意线程执行任意代码。如果__del__()需要锁定或调用任何其他阻塞资源,则可能会死锁,因为资源可能已被中断执行的代码占用__del__()
  • __del__()可以在解释器关闭期间执行。因此,它需要访问的全局变量(包括其他模块)可能已被删除或设置为None. Python 保证在删除其他全局变量之前,先从其模块中删除名称以单下划线开头的全局变量;如果不存在对此类全局变量的其他引用,这可能有助于确保调用该方法时导入的模块仍然可用__del__()

要点是,__del__不可靠(第#1点意味着你可能会遇到模块导入锁的问题,第#2点意味着每个该死的东西都可能在关闭期间损坏),并且当解释器关闭时,你不能,也不应该' t,期望能够导入任何东西。解决方案是避免__del__(正如您所见,这是相当不可靠的)而支持更具确定性的东西,例如使用and和 using语句为您的类实现上下文管理器协议,因此清理发生在确定性的时间点(在解释器关闭)。__enter____exit__with

或者,不要推迟导入,并将它们缓存在不会被清除的地方,例如使用以下黑客:

import os  # Deferred imports are usually a bad idea anyway

class foo:
    def __del__(self, os=os):  # Fake argument with default caches os separate from globals
        # do stuff with os cached in location it definitely won't be preemptively cleared
Run Code Online (Sandbox Code Playgroud)