Context managers use with for automatic setup and cleanup. Use @contextmanager to create one from a generator function. Code before yield runs on entry and code after yield runs on exit, even if an error occurs.
Context Managers (with)
from contextlib import contextmanager
@contextmanager
def timer():
import time
start = time.time()
yield
print(f"Elapsed: {time.time()-start:.2f}s")
with timer():
# some code
sum(range(10**7))