The with statement in Python
By Flavio Copes
Learn how the with statement in Python simplifies exception handling, automatically closing a file you open with open() so you do not have to call close().
The with statement runs a block of code and guarantees the cleanup happens at the end, even if an exception is raised in the middle. It’s the standard way to work with resources that need to be released, like open files.
The classic example is files. Each time we open a file, we must remember to close it. If our code raises an exception before the close() call, the file stays open, and we leak a file handle.
Instead of writing:
filename = '/Users/flavio/test.txt'
try:
file = open(filename, 'r')
content = file.read()
print(content)
finally:
file.close()
You can write:
filename = '/Users/flavio/test.txt'
with open(filename, 'r') as file:
content = file.read()
print(content)
The file is closed automatically when the block ends. Same guarantee as the try/finally version, with less code and no way to forget the cleanup.
There’s also a subtle bug in the try/finally version: if open() itself fails, file was never assigned, and the finally block raises a NameError on top of the original error. with doesn’t have this problem.
How does it work?
with works with any object that implements the context manager protocol: an __enter__() method that runs when the block starts, and an __exit__() method that runs when the block ends.
File objects implement this protocol, and their __exit__() closes the file. That’s why the example above works.
Opening multiple files
You can open more than one file in a single statement. Handy when copying content from one file to another:
with open('draft.txt', 'r') as source, open('final.txt', 'w') as destination:
destination.write(source.read())
Both files are closed when the block ends.
A common mistake
The variable defined with as still exists after the block, but the file behind it is closed. Reading from it raises an error:
with open('/Users/flavio/test.txt', 'r') as file:
content = file.read()
file.read()
# ValueError: I/O operation on closed file.
Do all your reading inside the block. Keep the data you extracted (the content variable here) for anything you need later.
with is not just for files. Database connections, locks in threaded code, and temporary directories all use context managers, and you handle them all with this same pattern.
Related posts about python: