Lesson 10 of 10
Guaranteed cleanup
- 15 min
- 6 checks
- 3 hints
- Go to task
Goal
The with statement guarantees cleanup, whatever happens
Explanation
The current code acquires the lock and then releases it, with a line in between that can fail. If it does, execution never reaches release, the lock stays held forever, and every call after that fails. Run the code and see for yourself.
with guarantees the cleanup. It calls __enter__ on the way in, puts whatever that returns into the variable after as, then calls __exit__ on the way out, whatever the reason, whether the code finished normally or raised an exception. That's how with open(...) works: you write the cleanup once in the class instead of writing try/finally everywhere the class is used.
The trap is that __exit__ receives the exception details, and if it returns True it hides the exception as though it never happened. So return nothing from it, and let the error carry on to whoever handles it. If you'd rather write a function than a class, there's a shorter way: @contextlib.contextmanager with yield inside try/finally. Forget the finally there and you're back to the same problem.
Your task
Give Lock an __enter__ method that acquires the lock and returns self, and an __exit__ method that always releases it without hiding the error. Then rewrite update using with lock:.
Checks
6 checks- The lock is held inside the with block
- The as clause gives you the lock itself
- The lock is released on a normal exit
- The lock is released even if an error happens inside
- __exit__ doesn't hide the error
- update releases the lock despite the error