Eya*_*utz 6 python contextmanager python-decorators
我正在学习上下文管理器,并试图自己构建一个。以下是一个虚拟上下文管理器,它以读取模式打开一个文件(我知道我可以这样做with open(...): ...。这只是我构建的一个示例,旨在帮助我了解如何创建自己的上下文管理器):
@contextmanager
def open_read(path: str):
f = open(path, 'r')
print('open')
yield f
f.close()
print('closed')
def foo():
try:
with open_read('main.py') as f:
print(f.readline())
raise Exception('oopsie')
except Exception:
pass
print(f.readline())
foo()
Run Code Online (Sandbox Code Playgroud)
我希望这段代码能够打印:
open
<line 1 of a.txt>
closed
ValueError: I/O operation on closed file.
Run Code Online (Sandbox Code Playgroud)
但它打印的是:
open
<line 1 of a.txt>
<line 2 of a.txt>
Run Code Online (Sandbox Code Playgroud)
它没有关闭文件!
这似乎与 python 的文档相矛盾,该文档声明无论语句成功退出还是出现异常__exit__都会调用该函数:with
目的。退出(自身、exc_type、exc_value、回溯)
退出与该对象相关的运行时上下文。参数描述导致上下文退出的异常。如果上下文退出时没有异常,则所有三个参数都将为 None。
有趣的是,当我重新实现上下文管理器(如下所示)时,它按预期工作:
open
<line 1 of a.txt>
closed
ValueError: I/O operation on closed file.
Run Code Online (Sandbox Code Playgroud)
为什么我原来的实现没有成功?
该行f.close()永远不会到达(由于未处理的异常,我们提前退出该帧),然后异常在外帧(即在foo)中“处理”。
如果您希望它无论如何关闭,您必须像这样实现它:
@contextmanager
def open_read(path: str):
f = open(path, 'r')
try:
print('open')
yield f
finally:
f.close()
print('closed')
Run Code Online (Sandbox Code Playgroud)
但是,我想指出,内置函数open已经返回了上下文管理器,并且您可能正在重新发明 stdlib contextlib.closing。
| 归档时间: |
|
| 查看次数: |
715 次 |
| 最近记录: |