🐍 Python - Context Managers
Updated at 2018-06-10 21:57
Context managers are simplified but powerful try/finally
pattern. Context managers need to implement __enter__
and __exit__
. Exit method will be performed after any exceptions, return
or even sys.exit()
. You use context managers by using with
keyword.
class Greeting:
def __init__(self, text: str) -> None:
self.text: str = text
def __enter__(self) -> str:
return self.text
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
print('exit')
with Greeting('hello') as g:
assert g == 'hello'
# => exit
contextlib
has a helper decorator for turning a generator to a context manager.
from contextlib import contextmanager, closing
@contextmanager
def greeting(text: str) -> str:
try:
yield text
finally:
print('exit')
with greeting('hello') as g:
assert g == 'hello'
# => exit
# also, if we would yield a connection, a file or something else closeable,
# you can do the following so closing is done automatically
# when value goes out of scope
# with closing(connection):
# yield connection
The same context manager instance can be used multiple times to pass on state.
class Indenter:
def __init__(self, amount: int) -> None:
self.level = 0
self.amount = amount
def __enter__(self) -> 'Indenter':
self.level += 1
return self
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
self.level -= 1
def echo(self, text: str) -> None:
print(' ' * (self.level * self.amount) + text)
with Indenter(4) as indent:
indent.echo('hi!')
with indent:
indent.echo('hello')
with indent:
indent.echo('bonjour')
indent.echo('hey')
# => hi!
# => hello
# => bonjour
# => hey
Source
- Python Tricks The Book, Dan Bader
- Fluent Python, Luciano Ramalho