Context managers – the with statement
The try...finally statement is useful to ensure some cleanup code is run, even if an error is raised. There are many use cases for this, such as the following:
- Closing a file
- Releasing a lock
- Making a temporary code patch
- Running protected code in a special environment
The with statement factors out these use cases by providing a simple way to wrap a block of code with methods defined within the context manager. This allows us to call some code before and after block execution, even if this block raises an exception. For example, working with a file is often done like so:
>>> hosts = open('/etc/hosts') >>> try: ... for line in hosts: ... if line.startswith('#'): ... continue ... print(line.strip()) ... finally: ... hosts.close() ... 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost
By using the with statement, it can be rewritten into the following code, which is shorter and cleaner:
>>> with open('/etc/hosts') as hosts: ... for line in hosts: ... if line.startswith('#'): ... continue ... print(line.strip()) ... 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost
In the preceding example, the open() function is used as a context manager that ensures that the file will be closed after executing the for loop, even if some exception occurs in the process.
Some other common items from the Python standard library that are compatible with this statement are classes from the threading module:
- threading.Lock
- threading.RLock
- threading.Condition
- threading.Semaphore
- threading.BoundedSemaphore