如何防止模块被垃圾收集器删除或在__del__方法中重新导入

时间:2015-05-08 11:29:09

标签: python garbage-collection

我为日志模块编写了一个包装类,它有__del__method来删除程序结束时的日志文件。

我的程序将此日志文件从其他类复制到存档中,在下一次执行程序之前,在工作文件夹中没有日志文件很重要。但我无法将其从其他模块中删除,因为它们仍然使用记录器。

所以我使用了__del__方法。

def __del__(self):
    if self.config_object.logfile is not None:
        import os
        try:
            os.unlink(self.config_object.logfile)
        except (WindowsError, AttributeError):
            pass

我重新导入操作系统,因为有时在我的Logging类之前已经被垃圾收集器破坏了。这在python3.2

中工作正常

但是在切换到python3.4之后我看到了这样的错误:

  File "<frozen importlib._bootstrap>", line 2236, in _find_and_load
  File "<frozen importlib._bootstrap>", line 263, in __enter__
  File "<frozen importlib._bootstrap>", line 287, in _get_module_lock
  File "<frozen importlib._bootstrap>", line 173, in __init__
TypeError: 'NoneType' object is not callable

我试图阻止删除操作系统而不是重新导入操作系统但是失败了。

我试过这个想法: 使用os内部创建循环引用。在我的类中添加带os模块的字段。调用gc.disabled()direclty。 但他们都没有帮助。

所以我有两个问题。 首先是如何使用新的importlib在python 3.4中重新导入os,而python programm正在被垃圾收集器破坏。 第二是如何防止垃圾收集器删除os模块。

P.S。我知道使用上下文管理器比__del__好,并阅读关于这个问题的问题。当然,我可以更改程序逻辑,以避免删除日志文件的必要性。 所以日志这个问题只是唤醒我好奇心的一个例子。如果有人能够证明我的目标都是不可能的,那么它就是最好的答案。但是如果存在一个丑陋的unpythonic解决方案,我想知道它,即使它正在改变字节码直接或类似的东西。

2 个答案:

答案 0 :(得分:2)

您可以将对os.unlink()函数的引用绑定为默认参数,这样在挂钩运行时您仍然可以访问该函数:

def __del__(self, _os_unlink=os.unlink):
    if self.config_object.logfile is not None:
        import os
        try:
            _os_unlink(self.config_object.logfile)
        except (WindowsError, AttributeError):
            pass

但是,请注意,永远不能保证在Python关闭时执行挂钩。

另外,如果你需要调用恰好在纯python中实现的其他函数,那么你需要考虑那些函数可能正在使用已设置为{的依赖项{1}}此时此刻。您可能必须使用“捕获”引用重新实现这些功能,或者您必须仅为您的调用恢复依赖项。例如,None要求os.path.exists()仍然可用。在调用捕获的os.stat()函数之前,重新实现捕获os.stat的{​​{3}}或至少确保os.stat存在。

答案 1 :(得分:0)

在您的情况下,最好只使用使用tempfile模块创建的临时文件,而不是尝试管理您自己的临时文件。

在更抽象的意义上,你利用了python保证模块的私有全局变量(带有前导下划线)在其公共全局变量之前被删除的事实。例如

from os import unlink

class TempFileManager:
    def __init__(self):
        self.temp_files = []
    def __del__(self):
        for file_ in self.temp_files:
            # unlink still available as _temp_file_manager is deleted first
            unlink(file_)

_temp_file_manager = TempFileManager()

您可能还希望查看atexit模块,而不是依赖__del__语义。例如

import os
import atexit

file_ = ...

atexit.register(os.unlink, file_)