问题
After reading the with statement section of the language documentation of Python, I was wondering if it is correct to state that this Python code:
with EXPRESSION as TARGET:
SUITE
is equivalent to this one:
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)
Edit
The correct equivalent Python code (the real CPython implementation is in C) was actually given by Guido van Rossum himself in PEP 343:
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)
Since Python 3.6, this has changed a little: now the __enter__
function is loaded before the __exit__
function (cf. https://bugs.python.org/issue27100).
So my equivalent Python code had three flaws:
- The
__enter__
and__exit__
functions should be loaded before calling the__enter__
function. - The
__enter__
function should be called outside thetry
statement (cf. the note of point 4 in the language documentation). - The
else
clause should instead be afinally
clause, to handle the case when there is a non-local goto statement (break
,continue
,return
) insuite
.
However I don’t understand why the equivalent Python code in PEP 343 puts the finally
clause in an outer try
statement instead of in the inner try
statement?
回答1:
Nick Coghlan, the other author of PEP 343, answered on the Python bug tracker:
It's a matter of historical timing: PEP 343 was written before try/except/finally was allowed, when try/finally and try/except were still distinct statements.
However, PEP 341 was also accepted and implemented for Python 2.5, allowing for the modern try/except/finally form: https://docs.python.org/dev/whatsnew/2.5.html#pep-341-unified-try-except-finally
So the modern try
statement equivalent Python code of the with
statement is this one:
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)
来源:https://stackoverflow.com/questions/59322585/what-is-the-equivalent-try-statement-of-the-with-statement-in-python