Nick Coghlan ncoghlan-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org writes:
On Wed, Oct 19, 2011 at 1:14 PM, Chris Rebert pyideas-QkDgq5C4a+JWk0Htik3Jemail@example.com wrote:
On Tue, Oct 18, 2011 at 7:14 PM, Nikolaus Rath Nikolaus-BTH8mxji4b0@public.gmane.org wrote:
I often have code of the form:
def my_fun(): allocate_res1() try: # do stuff allocate_res2() try: # do stuff allocate_res3() try: # do stuff finally: cleanup_res3() finally: cleanup_res2() finally: cleanup_res1()
With increasing number of managed resources, the indentation becomes really annoying, there is lots of line noise, and I don't like the fact that the cleanup is so far away from the allocation.
Use the `with` statement and context managers. They were added for this exact situation. See http://www.python.org/dev/peps/pep-0343/
Resulting code will resemble:
def func(): with alloc() as res1, alloc() as res2, alloc() as res3: # do stuff
Or, to more closely mirror the original example:
# Define these wherever the current resources are defined @contextlib.contextmanager def cm1(): res1 = allocate_res1() try: yield res1 finally: cleanup_res1() @contextlib.contextmanager def cm2(): res2 = allocate_res2() try: yield res2 finally: cleanup_res2() @contextlib.contextmanager def cm3(): res3 = allocate_res3() try: yield res2 finally: cleanup_res3() def func(): with cm1() as res1: # do stuff with cm2() as res2: # do stuff with cm3() as res3: # do stuff
Indeed, that works. But I do you really consider this code nicer than the original one? I think a simple line count answers the question :-).