在阅读了Python语言文档的with
statement section之后,我想知道声明以下Python代码是否正确:
with EXPRESSION as TARGET:
SUITE
与此等效:
try:
manager = (EXPRESSION)
value = manager.__enter__()
TARGET = value # only if `as TARGET` is present in the with statement
SUITE
except:
import sys
if not manager.__exit__(*sys.exc_info()):
raise
else:
manager.__exit__(None, None, None)
Guido van Rossum本人在PEP 343中给出了正确的等效Python代码(真正的CPython实现在C语言中):
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)
自Python 3.6以来,这已经发生了一些变化:现在__enter__
函数之前(参见https://bugs.python.org/issue27100)先于{em>加载了__exit__
函数。
所以我等效的Python代码有三个缺陷:
__enter__
函数之前先加载__exit__
和__enter__
函数。__enter__
函数应在try
语句之外调用(参见语言文档中第4点的注释)。else
子句应该是finally
子句,以处理存在非本地goto语句(break
,continue
,{{1 }}})。 但是我不明白为什么PEP 343中的等效Python代码将return
子句放在外部suite
语句而不是内部finally
语句中? / strong>
答案 0 :(得分:1)
PEP 343的另一作者尼克·科格兰(Nick Coghlan)在Python bug tracker上回答:
这与历史时机有关:PEP 343是在 当try / finally和try / except分别为try / except / finally时 仍然是不同的陈述。
但是, 也接受并实现了针对Python 2.5的PEP 341, 允许使用现代的try / except / final形式: https://docs.python.org/dev/whatsnew/2.5.html#pep-341-unified-try-except-finally
因此,try
语句的现代with
语句等效的Python代码是这样的:
manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)
hit_except = False
try:
TARGET = value # only if `as TARGET` is present in the with statement
SUITE
except:
import sys
hit_except = True
if not exit(manager, *sys.exc_info()):
raise
finally:
if not hit_except:
exit(manager, None, None, None)