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?