在Python中,如果我在“ with”块内返回文件,文件是否仍会关闭?


Answers:


238

是的,它的作用就像一个finally块接一个try块,也就是说,它总是执行(除非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).

但是,值得一提的是,如果open()不将整个with块放入try..except通常不是您想要的块中,就无法轻松捕获调用引发的异常。


8
else可以添加以with解决该try with except问题。编辑:添加到语言
rplnt 2012年

7
我不知道它是否相关,但是据我所知Process.terminate(),它是不能保证调用finally语句的少数(唯一的)方案之一: “请注意,退出处理程序和finally子句等将不会被被处决。”
里克·波吉

os._exit有时使用@RikPoggi- 退出Python进程而不调用清除处理程序。
Acumenus

2
也许有点嘲弄蛇,但是如果我从with块内返回生成器表达式,只要生成器保持产生值,保证就成立吗?只要有什么参考呢?即我是否需要对del持有生成器对象的变量使用或分配其他值?
2016年

1
@davidA关闭文件后,引用仍然可以访问;但是,使用引用将数据拉入/拉出文件的任何尝试都会产生:ValueError: I/O operation on closed file.
RWDJ

36

是。

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中


30
一个有趣的实验来证明您从finally钥匙中获得的保证是:def test(): try: return True; finally: return False
Ehsan Kia 2014年

20

是。更一般地,如果在上下文内部发生__exit__了“ with”语句上下文管理器,该方法的确会被调用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。这样,上下文管理器不会被绕过。


4

是的,但是在其他情况下可能会有一些副作用,因为它可能会在__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'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.