Context Managers and else Blocks
Source: Fluent Python, 2nd Edition — Chapter 18 by Luciano Ramalho
Hettinger: with is not the shallow with of BASIC. It is setup and teardown, as fundamental as a subroutine. This chapter also covers else on for / while / try (a then-clause wearing the wrong keyword) and a short note on match OR-patterns. A full Scheme interpreter is a book-length case study; we keep pattern matching to the | rule.
else beyond if
Read it as then, not “otherwise”:
for/else:elseruns if the loop finished (nobreak).while/else:elseruns if the condition went falsy (nobreak).try/else:elseruns if thetrybody raised nothing. Exceptions inelseare not caught by the precedingexcept.
return / break / continue / an exception skip else.
Banana hunt without a flag:
for item in my_list:
if item == 'banana':
break
else:
raise ValueError('no banana')
Put only the risky call in try; put the “success path” in else so you are not accidentally catching errors from after_call().
EAFP (easier to ask forgiveness): try, then except. LBYL (look before you leap): many ifs. LBYL races in threads (if key in d: d[key]). EAFP is why try/else matters.
Context managers and with
with is try/finally with an object in charge. __enter__ at the start; __exit__ at the end (exception, return, sys.exit, or a clean finish).
The object after with is the manager. as name binds whatever __enter__ returns — often self (open), sometimes another object, sometimes None. __exit__ always runs on the manager, not on the as value.
__exit__(exc_type, exc_value, traceback) gets three Nones on success. Return True to swallow the exception; anything else (including implicit None) lets it propagate.
Uses: files, sqlite transactions, threading locks, decimal.localcontext, unittest.mock.patch. contextlib.redirect_stdout / redirect_stderr swap streams for a block.
You can call __enter__ / __exit__ by hand to see the protocol.
The as target
1 / 1with Mgr() as x binds x to
Pick an answer to see if you are right.
contextlib
Look here before writing a class: closing (objects with .close only), suppress, nullcontext (3.7, for optional managers), @contextmanager, AbstractContextManager (3.6), ContextDecorator (also a decorator), ExitStack (enter N managers, exit LIFO). 3.7+ async twins for async with.
@contextmanager
One yield: code before is __enter__; the yielded value is the as target; code after is __exit__. The decorator wraps the generator in a helper class (next to the yield; on the way out throw if there was an exception, else next).
Always try/finally around yield — users can do anything in the block. Default vs a class: @contextmanager suppresses exceptions sent into the generator unless you re-raise. A class __exit__ suppresses only if it returns True.
That yield is a coroutine pause, not iteration. Pieters’ inplace file rewriter: backup and two handles before yield; restore on failure after.
OR-patterns in match
case int(x) | float(x): matches either class; all branches must bind the same names. | here is not bitwise or. Class pattern int(x) is isinstance plus capture.
The number case is optional; the tests only hit signs and other.