[Python-ideas] Avoiding nested for try..finally: atexit for functions?

Nikolaus Rath Nikolaus at rath.org
Wed Oct 19 15:38:47 CEST 2011


Nick Coghlan <ncoghlan-Re5JQEeQqe8AvxtiuMwx3w at public.gmane.org> writes:
> On Wed, Oct 19, 2011 at 1:14 PM, Chris Rebert <pyideas-QkDgq5C4a+JWk0Htik3J/w at public.gmane.org> wrote:
>> On Tue, Oct 18, 2011 at 7:14 PM, Nikolaus Rath <Nikolaus-BTH8mxji4b0 at public.gmane.org> wrote:
>>> Hello,
>>>
>>> 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()
>>>
>>>    return
>>>
>>> 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 :-).


Best,

   -Nikolaus

-- 
 »Time flies like an arrow, fruit flies like a Banana.«

  PGP fingerprint: 5B93 61F8 4EA2 E279 ABF6  02CF A9AD B7F8 AE4E 425C



More information about the Python-ideas mailing list