我为日志模块编写了一个包装类,它有__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解决方案,我想知道它,即使它正在改变字节码直接或类似的东西。
答案 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_)