在Python中,如果返回"with"Block,文件还会关闭吗?

考虑以下几点:

with open(path, mode) as f:
return [line for line in f if condition]

文件将被正确关闭,还是使用return以某种方式绕过上下文管理器?

83330 次浏览

是的,它的作用就像try块之后的finally块,即它总是执行(当然,除非python进程以一种不寻常的方式终止)。

它也在pep - 343的一个示例中提到,该示例是with语句的规范:

with locked(myLock):
# Code here executes with myLock held.  The lock is
# guaranteed to be released when the block is left (even
# if via return or by an uncaught exception).

然而,值得注意的是,如果不将整个with块放入try..except块中,就不容易捕获open()调用抛出的异常,这通常不是我们想要的。

是的。

def example(path, mode):
with open(path, mode) as f:
return [line for line in f if condition]

. .基本上相当于:

def example(path, mode):
f = open(path, mode)


try:
return [line for line in f if condition]
finally:
f.close()

更准确地说,上下文管理器中的__exit__方法总是在退出块时被调用(不管异常、返回等)。文件对象的__exit__方法只调用f.close()(例如在CPython中)

是的。更一般地,使用语句上下文管理器__exit__方法确实会在上下文内部发生return时被调用。这可以用以下方法进行测试:

class MyResource:
def __enter__(self):
print('Entering context.')
return self


def __exit__(self, *exc):
print('EXITING context.')


def fun():
with MyResource():
print('Returning inside with-statement.')
return
print('Returning outside with-statement.')


fun()

输出结果为:

Entering context.
Returning inside with-statement.
EXITING context.

上面的输出确认了__exit__被调用,尽管早期有return。因此,不会绕过上下文管理器。

是的,但是在其他情况下可能会有一些副作用,因为它可能应该在__exit__块中做一些事情(比如刷新缓冲区)

import gzip
import io


def test(data):
out = io.BytesIO()
with gzip.GzipFile(fileobj=out, mode="wb") as f:
f.write(data)
return out.getvalue()


def test1(data):
out = io.BytesIO()
with gzip.GzipFile(fileobj=out, mode="wb") as f:
f.write(data)
return out.getvalue()


print(test(b"test"), test1(b"test"))


# b'\x1f\x8b\x08\x00\x95\x1b\xb3[\x02\xff' b'\x1f\x8b\x08\x00\x95\x1b\xb3[\x02\xff+I-.\x01\x00\x0c~\x7f\xd8\x04\x00\x00\x00'