Context managers are objects that sandwich a block of code between a common enter code block and exit code block. They're powered by the with
block:
with my_context_manager() as my_context:
do_something_here(my_context)
Whenever you see a with
block, a context manager is being used (the thing right after the with
and before that as
is the context manager: my_context_manager
).
Context managers are most commonly used when you have some "tear down" code that needs to be executed regardless of whether an exception has occurred before that point in your code.
For example, file objects can act as a context manager to ensure the file is always closed after a particular with
block exits.
This try
-finally
construct ensures our file is always closed, even if an error occurs while reading from it:
my_file = open('my_file.txt')
try:
get_data = my_file.read()
finally:
my_file.close()
Because file objects implement the context manager protocol, we can instead use the file object in a with
block:
with open('my_file.txt') as my_file:
get_data = my_file.read()
When you use a file object in a with
block, Python doesn't call close
automatically.
Instead it calls __enter__
(when entering the with
block) and __exit__
(when exiting the block).
You can think of this:
with open('my_file.txt') as my_file:
get_data = my_file.read()
As sort of like this:
my_file = open('my_file.txt')
my_file.__enter__()
try:
get_data = my_file.read()
finally:
my_file.__exit__()
Technically it's actually more like this:
_context = open('my_file.txt')
my_file = _context..__enter__()
try:
get_data = my_file.read()
except BaseException as _e:
if not _context.__exit__(type(_e), _e, _e.__traceback__):
raise
else:
_context.__exit__()
But we don't often need to worry about all that complexity at once.
with ... as
syntaxNeed to fill-in gaps in your Python skills?
Sign up for my Python newsletter where I share one of my favorite Python tips every week.
Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.