Python 关闭打开的文件的装饰程序

Python 关闭打开的文件的装饰程序,python,Python,我想写一个装饰关闭所有打开的文件。例如: @close_files def view(request): f = open('myfile.txt').read() return render('template.html') 忽略任何线程安全的东西,我怎么能编写这样一个修饰符来在函数返回后关闭任何打开的文件呢?我对编写上下文管理器不感兴趣,但类似这样: def close_files(func): @wraps(func) def wrapper_close_

我想写一个装饰关闭所有打开的文件。例如:

@close_files
def view(request):
    f = open('myfile.txt').read()
    return render('template.html')
忽略任何线程安全的东西,我怎么能编写这样一个修饰符来在函数返回后关闭任何打开的文件呢?我对编写上下文管理器不感兴趣,但类似这样:

def close_files(func):
    @wraps(func)
    def wrapper_close_files(*args):
        return_value = func(*args, **kwargs)
        # close open files here?
        return return_value
    return wrapper_close_files
with open('myfile.txt') as _f: f = _f.read()
在您的回答中,请不要提出以下建议:

def close_files(func):
    @wraps(func)
    def wrapper_close_files(*args):
        return_value = func(*args, **kwargs)
        # close open files here?
        return return_value
    return wrapper_close_files
with open('myfile.txt') as _f: f = _f.read()

我想问的是,如果我们无法直接访问引用文件(处理程序)的变量,如何使用decorator关闭这些文件。

我认为可以使用它遍历文件打开的代码,并尝试关闭发现已打开的任何文件。

根据python文档3.6: 如果未使用with关键字,则应调用f.close()关闭该文件,并立即释放该文件使用的所有系统资源。如果不显式关闭文件,Python的垃圾收集器最终将销毁该对象并为您关闭打开的文件,但该文件可能会保持打开状态一段时间。另一个风险是,不同的Python实现将在不同的时间进行清理

因此,如果您想这样做,您需要一个从内置模块捕获open命令的装饰器。但是,由于我们不知道将打开多少文件,因此可以使用ExitStack。因此,可以使用一个函数将文件句柄保持在ExitStack上下文中

我的版本是:

def close_opened_files(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
    import builtins
    _open = getattr(builtins, 'open')
    try:
        with contextlib.ExitStack() as stack:
            def myopen(*args, **kwargs):
                f = stack.enter_context(_open(*args, **kwargs))
                return f
            setattr(builtins, 'open', myopen)
            ret = func(*args, **kwargs)
        return ret
    finally:
        setattr(builtins, 'open', _open)
return wrapper
在decorator结束时,应该在内置模块中恢复原来的open函数

这种方法的一个问题是:在
func
内部调用的函数以及使用
open
函数的函数在decorator结束时也会关闭它们的文件,即使它表示错误

以下是一些例子:

以下示例显示了读取和写入操作,以及函数中关闭的文件

@close_opened_files
def test_write(fn1, fn2=None):
    f1 = open(fn1, 'w')
    print('Hello world', file=f1)
    if fn2:
        f2 = open(fn2, 'w')
        print('foo-bar', file=f2)
        f2.close()

@close_opened_files
def test_read(fn1, fn2=None):
    f1 = open(fn1, 'r')
    for line in f1: print(line)
    if fn2:
        f2 = open(fn2, 'r')
        for line in f2: print(line)
        f2.close()

test_write('file1.txt', 'file2.txt')
test_read('file1.txt', 'file2.txt')

try: test_read('non_exist_filename.txt')
except FileNotFoundError as ex: print(ex)

try: test_exception('file1.txt')
except RuntimeError as ex: print(ex)
最后这些示例显示了异常“无文件存在”或发生的任何其他异常下的装饰器。
最后一种情况是,在引发异常之前,文件将被关闭。

为什么?你拒绝了一个上下文管理器,我马上就被甩了,我看到你在最后一个问题中也使用了Flask。你到底想解决什么问题?@roganjosh——当然。我只是想知道这是怎么做到的。在代码中,我实际上使用了context manager.Mmm。我怀疑这是可能的,但这可能是需要检查全局范围内的文件处理程序(“关闭所有打开的文件的…”)的讨厌代码。我不能说我理解其中的动机,但也许你的好奇心会带来一些见解。我不是一个悲观的选民,但我真的很难理解弹劾法案,那么如何实施呢?