Skip to main content

Github

🐍 Context Managers in Python

Context Managers in Python #

Context managers allow you to allocate and release resources precisely when you want to. The most common use is with the with statement.

The with Statement #

Automatically handle resource cleanup:

# Without context manager
file = open('example.txt', 'r')
try:
 content = file.read()
 print(content)
finally:
 file.close()
# With context manager
with open('example.txt', 'r') as file:
 content = file.read()
 print(content)
# File is automatically closed

Creating Context Managers with Classes #

Implement enter and exit methods:

class DatabaseConnection:
 def __init__(self, host, port):
 self.host = host
 self.port = port
 self.connection = None
 
 def __enter__(self):
 print(f"Connecting to {self.host}:{self.port}")
 self.connection = self._create_connection()
 return self.connection
 
 def __exit__(self, exc_type, exc_val, exc_tb):
 print("Closing connection")
 if self.connection:
 self.connection.close()
 
 # Return False to propagate exceptions
 # Return True to suppress exceptions
 return False
 
 def _create_connection(self):
 # Simulate connection creation
 return {"status": "connected"}
# Usage
with DatabaseConnection('localhost', 5432) as conn:
 print(f"Connection status: {conn['status']}")

Using contextlib #

Create context managers with the contextlib module:

from contextlib import contextmanager
@contextmanager
def file_manager(filename, mode):
 print(f"Opening {filename}")
 file = open(filename, mode)
 try:
 yield file
 finally:
 print(f"Closing {filename}")
 file.close()
# Usage
with file_manager('test.txt', 'w') as f:
 f.write('Hello, World!')
# Timer context manager
import time
@contextmanager
def timer(label):
 start = time.time()
 try:
 yield
 finally:
 end = time.time()
 print(f"{label}: {end - start:.2f} seconds")
with timer("Download"):
 # Simulate work
 time.sleep(2)

Multiple Context Managers #

Handle multiple resources in one statement:

# Multiple with statements (old way)
with open('input.txt', 'r') as infile:
 with open('output.txt', 'w') as outfile:
 outfile.write(infile.read())
# Multiple managers in one statement (Python 3+)
with open('input.txt', 'r') as infile, \
 open('output.txt', 'w') as outfile:
 outfile.write(infile.read())
# Using contextlib.ExitStack
from contextlib import ExitStack
def process_files(filenames):
 with ExitStack() as stack:
 files = [stack.enter_context(open(fname)) for fname in filenames]
 # All files are automatically closed when exiting
 for f in files:
 print(f.read())

Exception Handling #

Context managers can handle exceptions:

class ErrorHandler:
 def __enter__(self):
 return self
 
 def __exit__(self, exc_type, exc_val, exc_tb):
 if exc_type is None:
 print("No errors occurred")
 return False
 
 if exc_type == ValueError:
 print(f"Handled ValueError: {exc_val}")
 return True # Suppress the exception
 
 # Let other exceptions propagate
 return False
# Usage
with ErrorHandler():
 raise ValueError("This will be suppressed")
 print("This won't print")
print("Execution continues")

Async Context Managers #

Context managers for async code:

class AsyncDatabaseConnection:
 async def __aenter__(self):
 print("Connecting asynchronously")
 # await actual connection
 return self
 
 async def __aexit__(self, exc_type, exc_val, exc_tb):
 print("Disconnecting asynchronously")
 # await actual disconnection
 return False
# Usage with async/await
async def main():
 async with AsyncDatabaseConnection() as conn:
 # Do async work
 pass
# Using contextlib for async
from contextlib import asynccontextmanager
@asynccontextmanager
async def async_timer(label):
 import asyncio
 start = asyncio.get_event_loop().time()
 try:
 yield
 finally:
 end = asyncio.get_event_loop().time()
 print(f"{label}: {end - start:.2f} seconds")
async def example():
 async with async_timer("Operation"):
 await asyncio.sleep(1)

Common Use Cases #

Practical applications of context managers:

# 1. Lock management
from threading import Lock
lock = Lock()
with lock:
 # Critical section
 pass
# 2. Directory changes
import os
from contextlib import contextmanager
@contextmanager
def change_dir(path):
 old_dir = os.getcwd()
 os.chdir(path)
 try:
 yield
 finally:
 os.chdir(old_dir)
with change_dir('/tmp'):
 # Work in /tmp
 pass
# Back to original directory
# 3. Temporary environment variables
@contextmanager
def temp_env_var(key, value):
 old_value = os.environ.get(key)
 os.environ[key] = value
 try:
 yield
 finally:
 if old_value is None:
 del os.environ[key]
 else:
 os.environ[key] = old_value
# 4. Database transactions
@contextmanager
def transaction(connection):
 connection.begin()
 try:
 yield connection
 connection.commit()
 except Exception:
 connection.rollback()
 raise
with transaction(db_connection) as conn:
 conn.execute("INSERT INTO ...")

Related

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /