Python Basics — Context Managers
Context Managers
The with statement is the proper way to work with files in Python. It automatically handles cleanup — closing files, releasing resources — even if an error occurs.
The Problem Without with
# ❌ Manual approach — risky
f = open("data.txt", "r")
content = f.read()
# What if an error happens here? File stays open!
f.close()
# ❌ Slightly better but verbose
f = open("data.txt", "r")
try:
content = f.read()
finally:
f.close()
The with Statement (The Proper Way)
# ✅ Clean, safe, automatic
with open("data.txt", "r") as f:
content = f.read()
# File is automatically closed here — even if an error occurred!
What happens:
open()returns a file object- The file is assigned to
f - The code block runs
- When the block exits (normally or due to an error),
f.close()is called automatically
Why Context Managers Matter
# Without context manager — file might stay open
def read_unsafe():
f = open("big_file.txt")
data = f.read()
# If an exception occurs here, f is never closed
process(data) # potential error
f.close() # never reached if process() fails
# With context manager — always closed
def read_safe():
with open("big_file.txt") as f:
data = f.read()
process(data) # even if this fails, f is closed
Multiple Files in One with Block
# Python 3.1+
with open("input.txt", "r") as infile, open("output.txt", "w") as outfile:
for line in infile:
outfile.write(line.upper())
# Python 3.10+ — parenthesized context managers
with (
open("input.txt", "r") as infile,
open("output.txt", "w") as outfile,
):
for line in infile:
outfile.write(line.upper())
Practical Example: File Copy
with open("source.txt", "r") as src, open("dest.txt", "w") as dst:
for line in src:
dst.write(line)
print("File copied!")
Verifying the File Is Closed
with open("sample.txt", "r") as f:
print(f"Inside: closed = {f.closed}") # False
content = f.read()
print(f"Outside: closed = {f.closed}") # True
contextlib Basics
The contextlib module provides utilities for creating context managers:
contextlib.suppress — Ignore Specific Exceptions
from contextlib import suppress
# Instead of:
try:
os.remove("temp.txt")
except FileNotFoundError:
pass
# Use:
import os
from contextlib import suppress
with suppress(FileNotFoundError):
os.remove("temp.txt")
contextlib.redirect_stdout — Capture Print Output
from contextlib import redirect_stdout
import io
output = io.StringIO()
with redirect_stdout(output):
print("This goes to the variable, not the screen")
captured = output.getvalue()
print(f"Captured: {captured.strip()}")
# Captured: This goes to the variable, not the screen
Context Managers Beyond Files
The with statement isn’t just for files — many Python objects support it:
# Database connections
import sqlite3
with sqlite3.connect("my_database.db") as conn:
cursor = conn.cursor()
cursor.execute("SELECT 1")
# Connection auto-committed and closed
# Thread locks
import threading
lock = threading.Lock()
with lock:
# Only one thread can be here at a time
shared_resource += 1
Summary
- Always use
withwhen working with files — it’s the Python way - The
withblock guaranteesclose()is called, even on errors - Multiple files can be opened in a single
withstatement contextlibprovides extra tools:suppress,redirect_stdout, and more- Context managers work beyond files: databases, locks, network connections
- Rule: If you see
open()withoutwith, it’s a code smell
Next up: CSV Files →