对系统资源使用上下文管理器有错吗?
Is it ever wrong to use a context manager with system resources?
试图在更深层次上理解事物。
如果我打开一个文件,或者一个网络请求,tensorflow 会话,或者任何可以用 with
语句处理的东西;有没有 曾经 我不应该使用 with
语句的时候?
例如,有没有什么时候我应该使用更通用/通用的 try
except
结构?
我真正的问题是,with
真正作用的底层结构是什么?我读了一些不错的 helpful hints as well as the documentation itself,但 with
的一些内部工作原理对我来说仍然有点像黑魔法。我正在尝试揭开神奇成分的神秘面纱。
我总是去 Python 增强建议 (PEP) 来理解 python 中的概念,因为与文档相比,它们更侧重于事物的概念推理,并且通常直接解决:
- 新功能/更改的原因。
- 如何使用现有代码完成/它如何影响现有代码。
因为您对实现方面感兴趣,这里是 PEP 343 - the "with" statement 的相关成果:
Specification: The 'with' Statement
A new statement is proposed with the syntax:
with EXPR as VAR:
BLOCK
(paragraph omitted - not really relevent for this question)
The translation of the above statement is:
mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(mgr, *sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(mgr, None, None, None)
因此 with 语句的内部工作原理与 try: finally
构造完全相同,只是语法更清晰,更难忘记关闭文件等。
不使用 with
语句的原因如下:如果 failure/success 需要自定义清理。
通常您不需要知道在处理完文件后应该执行哪些清理。 with
语句无论如何都会关闭文件(除了 Python 没有机会进入上下文管理器的 __exit__
方法的情况,例如系统突然关闭或类似的非常特别的东西)。
但是,如果您需要执行一些 local 和 important 清理,那么使用 try/except/finally
可能 更有意义。此上下文中的一个重要关键字是:separation of concerns.
假设您调用一个函数,该函数假设创建了一个不受 Pythons GC 管理的对象,并打开一个文件并尝试将其写入文件。在这种情况下,您需要执行比打开和关闭文件更多的清理工作:
def func():
bad_object = create_object_that_cannot_be_cleaned_by_pythons_gc():
try:
with open(filename, 'w') as file:
file.write(bad_object.to_string())
finally:
bad_object.delete()
我真的很难想出一个例子,其中使用 try/finally
而不是仅仅创建一个 contextmanager 是有好处的,我不确定我是否成功了(通常我会把这个例子实现为 contextmanager :-))。重要的部分应该是上下文管理器执行一个默认的清理操作,而不是本地化的自定义清理。
试图在更深层次上理解事物。
如果我打开一个文件,或者一个网络请求,tensorflow 会话,或者任何可以用 with
语句处理的东西;有没有 曾经 我不应该使用 with
语句的时候?
例如,有没有什么时候我应该使用更通用/通用的 try
except
结构?
我真正的问题是,with
真正作用的底层结构是什么?我读了一些不错的 helpful hints as well as the documentation itself,但 with
的一些内部工作原理对我来说仍然有点像黑魔法。我正在尝试揭开神奇成分的神秘面纱。
我总是去 Python 增强建议 (PEP) 来理解 python 中的概念,因为与文档相比,它们更侧重于事物的概念推理,并且通常直接解决:
- 新功能/更改的原因。
- 如何使用现有代码完成/它如何影响现有代码。
因为您对实现方面感兴趣,这里是 PEP 343 - the "with" statement 的相关成果:
Specification: The 'with' Statement
A new statement is proposed with the syntax:
with EXPR as VAR: BLOCK
(paragraph omitted - not really relevent for this question)
The translation of the above statement is:
mgr = (EXPR) exit = type(mgr).__exit__ # Not calling it yet value = type(mgr).__enter__(mgr) exc = True try: try: VAR = value # Only if "as VAR" is present BLOCK except: # The exceptional case is handled here exc = False if not exit(mgr, *sys.exc_info()): raise # The exception is swallowed if exit() returns true finally: # The normal and non-local-goto cases are handled here if exc: exit(mgr, None, None, None)
因此 with 语句的内部工作原理与 try: finally
构造完全相同,只是语法更清晰,更难忘记关闭文件等。
不使用 with
语句的原因如下:如果 failure/success 需要自定义清理。
通常您不需要知道在处理完文件后应该执行哪些清理。 with
语句无论如何都会关闭文件(除了 Python 没有机会进入上下文管理器的 __exit__
方法的情况,例如系统突然关闭或类似的非常特别的东西)。
但是,如果您需要执行一些 local 和 important 清理,那么使用 try/except/finally
可能 更有意义。此上下文中的一个重要关键字是:separation of concerns.
假设您调用一个函数,该函数假设创建了一个不受 Pythons GC 管理的对象,并打开一个文件并尝试将其写入文件。在这种情况下,您需要执行比打开和关闭文件更多的清理工作:
def func():
bad_object = create_object_that_cannot_be_cleaned_by_pythons_gc():
try:
with open(filename, 'w') as file:
file.write(bad_object.to_string())
finally:
bad_object.delete()
我真的很难想出一个例子,其中使用 try/finally
而不是仅仅创建一个 contextmanager 是有好处的,我不确定我是否成功了(通常我会把这个例子实现为 contextmanager :-))。重要的部分应该是上下文管理器执行一个默认的清理操作,而不是本地化的自定义清理。