Source From Here
Discovering the quirks of Python's context manager
Python’s context managers are great for resource management and stopping the propagation of leaked abstractions. You’ve probably used it while opening a file or a database connection. Usually it starts with a with statement like this:
To write a custom context manager, you need to create a class that includes the __enter__ and __exit__ methods. Let’s recreate a custom context manager that will execute the same workflow as above:
Creating context managers by writing a class with __enter__ and __exit__ methods, is not difficult. However, you can achieve better brevity by defining them using contextlib.contextmanager decorator. This decorator converts a generator function into a context manager. The blueprint for creating context manager decorators goes something like this:
Let’s implement the same CustomFileOpen context manager with contextmanager decorator:
You can use context managers as decorators also. To do so, while defining the class, you have to inherit from contextlib.ContextDecorator class. Let’s make a RunTime decorator that will be applied on a file-opening function. The decorator will:
You can also create the same decorator via contextlib.contextmanager decorator.
You can nest multiple context managers to manage resources simultaneously. Consider the following dummy manager:
Notice the order they’re closed. Context managers are treated as a stack, and should be exited in reverse order in which they’re entered. If an exception occurs, this order matters, as any context manager could suppress the exception, at which point the remaining managers will not even get notified of this. The __exit__ method is also permitted to raise a different exception, and other context managers then should be able to handle that new exception.
Combining Multiple Context Managers
You can combine multiple context managers too. Let’s consider these two managers:
If you have variable numbers of context managers and you want to combine them gracefully, contextlib.ExitStack is here to help. Let’s rewrite context manager ab using ExitStack. This function takes the individual context managers and their arguments as tuples and returns the combined manager:
ExitStack can be also used in cases where you want to manage multiple resources gracefully. For example, suppose, you need to create a list from the contents of multiple files in a directory. Let’s see, how you can do so while avoiding accidental memory leakage with robust resource management:
If you are familiar with SQLALchemy, Python’s SQL toolkit and Object Relational Mapper, then you probably know the usage of Session to run a query. A Session basically turns any query into a transaction and makes it atomic. Context managers can help you write a transaction session in a very elegant way. A basic querying workflow in SQLAlchemy may look like this: