- Brief
- With statement
- Custom context manager
- __enter__, __exit__
- Handling exceptions
- Context manager with generator (@contextmanager)
- async with
- Asynchronous context manager
- External resources management (files, locks)
- Allows reusing the code that automatically manages the setup and teardown phases of a given operation
- Encapsulates standard uses of try ... finally statements in context managers
Using existing context managers.
Supports multiple context managers.
with open("hello.txt", mode="w") as file:
file.write("Hello, World!")
# equivalent to:
file = open("hello.txt", mode="w")
with file:
file.write("Hello, World!")
# multiple:
with open("input.txt") as in_file, open("output.txt", "w") as out_file:
...class ContextManager:
def __init__(self):
pass
def __enter__(self):
print("Entering the context...")
return "Hello, World!" # return value bounded to target variable (after 'with ... as' expression)
def __exit__(self, exc_type, exc_value, exc_tb): # can use: __exit__(self, *args, **kwargs):
print("Leaving the context...")
print(exc_type, exc_value, exc_tb, sep=" , ") # if no errors all 3 set to None
# return True # - if True is returned any errors are suppressed
with ContextManager() as hello: # remember to put: () !!!
print(hello)
# Output:
# Entering the context...
# Hello, World!
# Leaving the context...
# None , None , NoneFor previously defined context manager:
with ContextManager() as hello:
print(hello)
hello[100]
# Output:
# Entering the context...
# Hello, World!
# Leaving the context...
# <class 'IndexError'> , string index out of range , <traceback object at 0x...>
# ...
# IndexError: string index out of rangeTo handle this:
class ContextManager:
def __enter__(self):
print("Entering the context...")
return "Hello, World!"
def __exit__(self, exc_type, exc_value, exc_tb):
print("Leaving the context...")
if isinstance(exc_value, IndexError):
# Handle IndexError here...
print(f"An exception occurred in your with block: {exc_type.__name__}")
print(f"Exception message: {exc_value}")
return True # must return True to suppress exceptions !!!!
with ContextManager() as hello: # remember to put: () !!!
print(hello)
hello[100]
print("Continue normally from here...")
# Output:
# Entering the context...
# Hello, World!
# Leaving the context...
# An exception occurred in your with block: IndexError
# Exception message: string index out of range
# Continue normally from here...!!!! __exit__ must return True to suppress exceptions !!!!
__enter__ could return None !:
import sys
class RedirectedStdout:
def __init__(self, new_output):
self.new_output = new_output
def __enter__(self):
self.saved_output = sys.stdout
sys.stdout = self.new_output
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self.saved_outputThis 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.
from contextlib import contextmanager
@contextmanager
def context_manager():
print("Entering the context...") # __enter__
try:
yield "Hello, World!" # __enter__ return
finally:
print("Leaving the context...") # __exit__
with context_manager() as hello:
print(hello)
# Output:
# Entering the context...
# Hello, World!
# Leaving the context..Same with error handling
from contextlib import contextmanager
@contextmanager
def context_manager():
print("Entering the context...")
try:
raise TypeError
yield "Hello, World!"
except TypeError:
yield 'Error'
finally:
print("Leaving the context...")
with context_manager() as hello:
print(hello)
# Output:
# Entering the context...
# Error
# Leaving the context...Asynchronous version
...
__aenter__() and __aexit__()
...