【问题标题】:Python how to ensure that __del__() method of an object is called before the module dies?Python如何确保在模块死亡之前调用对象的 __del__() 方法?
【发布时间】:2013-02-05 20:25:05
【问题描述】:

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

【问题讨论】:

    标签: python module destructor


    【解决方案1】:

    正如我们之前告诉你的,你真的不应该依赖在解释器退出时调用__del__。正确执行此操作有两种选择:

    第一个是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

    第二种(better*) 方法是让你的类成为context manager,它会在你退出上下文时执行清理代码。那么您的代码将如下所示:

    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 是什么(以前从未听说过),__init__()__enter__ 之间的区别是什么,__del__() 和@987654333 之间的区别是什么@ 是。不过谢谢!
    • @Ray -- 在另一个问题上阅读您的 cmets 有助于我更好地理解您的问题。在这种情况下,我建议使用atexit.register 而不是上下文管理器。上下文管理器对于需要最终确定的代码来说是个好东西,所以我将保留这部分答案。
    • @mgilson。哦还有一件事,使用atexit 解决方案(我假设您的意思是模块atexit),您写del() 而不是__del__() 有什么原因吗?
    【解决方案2】:

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

    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 已被清理,则其他问题中的 __del__ 函数会失败),而函数本地函数与函数对象一起被清除,或者以防万一实例属性,与实例。

    【讨论】:

    • 但这仍然不能保证__del__ 会被实际调用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-20
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 2010-09-24
    相关资源
    最近更新 更多