Python如何确保在模块死亡之前调用对象的_del__()方法?

Python如何确保在模块死亡之前调用对象的_del__()方法?,python,module,destructor,Python,Module,Destructor,今天早些时候,我问了一个关于使用导入模块的对象的\uu del\uu()方法的问题。问题是\uu del\uu()想要使用模块os,但有时(并非总是)模块已经被删除。我被告知,当Python程序终止时,删除对象和模块的顺序可能是随机的,并且是未定义的。但是,对于我的应用程序,我确实需要确保在删除模块(在其中实例化对象)之前删除对象(我创建的类的实例)。有没有办法做到这一点?用关键字参数附加对函数的引用: import os class Logger(object): def _

今天早些时候,我问了一个关于使用导入模块的对象的
\uu del\uu()
方法的问题。问题是
\uu del\uu()
想要使用模块
os
,但有时(并非总是)模块已经被删除。我被告知,当Python程序终止时,删除对象和模块的顺序可能是随机的,并且是未定义的。但是,对于我的应用程序,我确实需要确保在删除模块(在其中实例化对象)之前删除对象(我创建的类的实例)。有没有办法做到这一点?

用关键字参数附加对函数的引用:

import os

class Logger(object):    
    def __del__(self, os=os):
        print "os: %s." %os
或者将其绑定到类属性:

import os

class Logger(object):
    def __init__(self):
        self.os = os

    def __del__(self):
        print "os: %s." % self.os
通过创建一个本地(足够)引用,Python将不会将
os
作为全局查找,而是使用一个本地引用,该引用分别存储在实例或函数本身中


全局函数在运行时被查找(这就是为什么如果
os
已经被清除,那么您的另一个问题中的
\uu del\uuu
函数将失败的原因),而本地函数将与函数对象一起清除,或者在实例属性的情况下,与实例一起清除。

正如我们之前告诉过您的,当解释器退出时,您真的不应该依赖于调用
\uu del\uu
。正确执行此操作有两个选项:

第一个是atexit

import os
import atexit

class Logger(object):   
    def on_exit(self):
        print "os: %s." % os

logger = Logger()
atexit.register(logger.on_exit)
这确保您的记录器在退出时完成


*再深入了解一下您的问题,因为您计划将单个实例绑定到一个定义实例类的模块,下面的上下文管理器解决方案对此不起作用,因为在整个程序执行过程中,没有办法留在上下文中。您需要使用
atexit.register
。然而,从程序设计的角度来看,如果重构代码允许的话,我更愿意使用上下文管理器来管理我的资源,而不是
atexit.register

第二种(更好的*)方法是使类成为一个在退出上下文时执行清理代码的类。那么您的代码将如下所示:

import os
class Logger(object):
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        print "os:",str(os)

with Logger() as logger:
    #do something ...

在这种情况下,为什么上下文管理器比atexit.register()更好?@thebjorn——因为上下文管理器使在函数中处理类变得更自然。使用
atexit.register
,您将在对象应已完成的很长时间后保留对象的引用。它还明确表示需要最终确定对象,这对于代码易读性来说是一件非常重要的事情。啊。谢谢@mgilson,但现在我必须弄清楚什么是
atexit
(以前从未听说过),以及
\uuuu init\uuuuuuuuu()
\uuu enter\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>之间的区别,以及
\uuuuuuuuuuuuuuuuuuuuuuuuuuu del()
和<。但是谢谢你@雷——阅读你对另一个问题的评论有助于我更好地理解你的问题。在这种情况下,我建议使用
atexit.register
而不是上下文管理器。上下文管理器对于需要最终确定的代码来说是一件很好的事情,所以我将留下我答案的这一部分。@mgilson。哦,还有一件事,对于
atexit
解决方案(我想你指的是模块
atexit
),你写
del()
而不是
\uu del\uuuuuuuuuuuuuuuuuuuuuuuuuu()
有什么原因吗?但这仍然不能保证
\uuuu del\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
会被调用。