The idea with is to make the “right thing” the least resistance. While the file example is the simplest, thread locks actually provide a more classic code example with a clear error:
try: lock.acquire() # do stuff finally: lock.release()
This code does not work - if the lock collection does not work, either an incorrect exception will occur (since the code will try to release the lock that it never received), or, even worse, if it is a recursive lock, it will be released early. The correct code is as follows:
lock.acquire() try: # do stuff finally: # If lock.acquire() fails, this *doesn't* run lock.release()
Using the with statement, it becomes impossible to get it wrong, because it is built into the context manager:
with lock:
Another place where the with statement helps a lot is similar to the main advantage of function and class decorators: it requires two-part code, which can be divided by an arbitrary number of lines of code (definition of a function for decorators, try block in the current case) and turns it into code "one part" where the programmer simply states what he is trying to do.
For brief examples, this doesn't seem like a big win, but it really matters a lot when viewing the code. When I see lock.acquire() in a piece of code, I need to scroll down and check the corresponding lock.release() . However, when I see with lock: such a check is not required - I immediately see that the lock will be released correctly.
source share