The contextlib module
allows easy creation of context managers to be used in with
clauses.
-
@contextmanager
Doc:
This function is a decorator that can be used to define a factory function for with statement context managers, without needing to create a class or separate
__enter__()
and__exit__()
methods.It needs to be used with a specific syntax:
try: yield ... # value finally: ... # exit
(Script available)
import os from contextlib import contextmanager def getcwd_abs(): return os.path.abspath(os.getcwd()) @contextmanager def cd(path): cwd = getcwd_abs() try: os.chdir(path) yield finally: os.chdir(cwd) if __name__ == '__main__': print(getcwd_abs()) with cd('..'): print(getcwd_abs()) print(getcwd_abs())
There is also @asynccontextmanager for
async with
. -
ContextDecorator
Doc:
A base class that enables a context manager to also be used as a decorator.
Context managers inheriting from
ContextDecorator
have to implement__enter__
and__exit__
as normal.__exit__
retains its optional exception handling even when used as a decorator.(Script available)
import os from contextlib import ContextDecorator def getcwd_abs(): return os.path.abspath(os.getcwd()) class CD(ContextDecorator): def __init__(self, path): self.original = getcwd_abs() self.path = os.path.abspath(path) def __enter__(self): os.chdir(self.path) def __exit__(self, exc_type, exc_val, exc_tb): os.chdir(self.original) @CD('..') def list_dir(path='.'): print(getcwd_abs()) print(os.listdir(path)) if __name__ == '__main__': with CD('..'): print(getcwd_abs()) print(os.listdir('.')) list_dir()