考虑以下内容:with open(path, mode) as f: return [line for line in f if condition] 文件是否会被正确关闭,或者使用 return 是否会以某种方式绕过上下文管理器?
考虑以下:
with open(path, mode) as f: return [line for line in f if condition]
文件是否会被正确关闭,或者是否以 return 某种方式绕过 上下文管理器 ?
return
是的,它的作用就像 finally 一个块接着一个 try 块,即它总是执行(当然,除非 python 进程以不寻常的方式终止)。
finally
try
的一个示例中也提到了这一点, PEP-343 这是该语句的规范 with :
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 ,而这通常不是人们想要的。
open()
try..except
可以将 else 添加到 with 中来解决 try with except 问题。编辑:添加到语言中
我不知道这是否相关,但据我所知,Process.terminate() 是少数(唯一?)不能保证调用 finally 语句的场景之一:\'请注意,退出处理程序和 finally 子句等将不会被执行。\'
有时会使用@RikPoggi os._exit - 它退出 Python 进程而不调用清理处理程序。
也许有点挑衅,但如果我从 with 块中返回一个生成器表达式,那么只要生成器继续产生值,保证是否有效?只要有任何东西引用它,保证是否有效?也就是说,我是否需要使用 del 或为保存生成器对象的变量分配不同的值?
@davidA 文件关闭后,引用仍然可以访问;但是,任何尝试使用引用从文件拉取/推送数据的尝试都会产生:ValueError: 对已关闭文件进行 I/O 操作。
是的。
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__
f.close()
一个有趣的实验可以展示您从 finally 关键字获得的保证:def test():try:return True; finally:return False。
是的。更一般地, __exit__ 如果 上下文中出现 from ,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 。因此,上下文管理器没有被绕过。
是的,但在其他情况下可能会有一些副作用,因为它可能应该在 __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'
在函数测试中,out.getvalue()发生在__exit__执行之前,所以结果符合预期。