Understanding Python Context-Managers for Absolute Beginners
Understand the WITH statement with lightsabers
You are definitely familiar with context managers—they use the with
statement:with open('somefile.text', 'r') as file:
data = file.read()
In this article we’ll focus on what happens when we call a context manager:
- What is a context manager?
- How does it work?
- What are its advantages?
- Creating your own context manager
Let’s code!
Before we take on some real-life example of code using the context manager we’ll understand the inner workings with a clear example: imagining we’re coding a lightsaber.
Setup: coding the lightsaber
I’m pretty sure everyone is familiar with those: the super-dangerous, red-hot plasma blade that slices through everything it touches. Before we use them to stab or slash we need to activate it and after we’re done using it we should always de-activate this insanely dangerous piece of equipment. In code:
Nothing too special: we keep track of two attributes: color
and active
. In this example color
is pretty decorative, active
however is pretty important since we can only use the slash()
and stab()
methods if we’ve activated our saber. We have two functions that control the state: turn_on()
and turn_off()
.
The way you’d use this code is like this:
This code is pretty high-maintenance; we mustn’t forget to turn on our lightsaber because it will throw an exception otherwise. Also we need to call the turn_off()
method every time. How can we make this code easier to use?
When to use a context manager?
In case of our lightsaber we always need to turn on the saber before we can do anything with it. Also we always need to turn if off because otherwise we cannot holster it and also energy prices are pretty high nowadays.
Remember that for turning the saber on and off we need to call the turn_on()
and turn_off()
methods. The lightsaber is an ideal use-case for the context manager since we need to perform an action every time before and/or after we use it.
Updating the lightsaber with a context manager
We’ll add two special ‘dunder-methods’ to our LightSaber class. Dunder-methods (double-underscore-methods) override functionality for built-in functions for custom classes. You might already know one: the __init__()
method!
We’ll add a __enter__
and __exit__
method so our Lightsaber class now looks like this:
As you’ll see the functions for turning the saber on and off are called in these enter and exit methods. We can now use the class like this:
As soon as we hit the with
statement we enter the __enter__
method which will turn on our lightsaber. Then we can slash and stab all we want. Once we exit the block of code the __exit__
method is called turns off our lightsaber.
The advantages are clear:
- Our code is much more concise.
- Our code is much easier to read.
- It automatically turns on when we want to start slashing and stabbing.
- It automatically turns off when we’re done murdering, preventing many injuries trying to holster it.
Context managers in the wild
The lightsaber is a bit of a toy-example but there are many occasions where a context manager is used. The example below details Python’s built-in functions for reading a file. The default way looks like this:file = open('somefile.txt')
content = file.read()
file.close()
If we don’t call file.close()
in the example above then our file will be occupied by our script. This means that no other processes can access it. Let’s use the context-manager:with open('somefile.txt') as file:
content = file.read()
The code above will close the file automatically. Also it is much easier to read.
Another example lies in database-connections. After we create a connection to a database and use it to read/write data to that database, we mustn’t forget to commit the data and close the connection. The regular implementation:cursor = conn.cursor()
cursor.execute("SELECT * FROM sometable")
cursor.close()
Thankfully many packages implement a context manager like this:with dbconnection.connect() as con:
result = con.execute("SELECT * FROM sometable")
The code above makes sure that the connection is closed as soon as we’re done with it. At the moment I’m in the process of creating a guide for connecting Python to a database; follow me if you are interested!
Conclusion
In this article we’ve covered the basics of context managers in Python and I hope to have shown you when and how to use one.
If you have any tips on improving this article; please comment! In the meantime, check out my other articles on all kinds of programming-related topics like these:
- Cython for absolute beginners — 30x faster code in two simple steps
- Why Python is so slow and how to speed it up
- Git for absolute beginners: understanding Git with the help of a video game
- Dramatically improve your database insert speed in a single line
- Docker for absolute beginners: the difference between an image and a container
- Docker for absolute beginners — what is Docker and how to use it (+ examples)
- Virtual environments for absolute beginners — what is it and how to create one (+ examples)
- Create and publish your own Python package
- 6 steps to make this Pandas dataframe operation 100 times faster
Happy coding!
— Mike
P.S: like what I’m doing? Follow me!