A "scopeguard" for Python

Alf P. Steinbach alfps at start.no
Thu Mar 4 17:27:03 EST 2010


* Mike Kent:
> On Mar 4, 12:30 pm, Robert Kern <robert.k... at gmail.com> wrote:
> 
>> He's ignorant of the use cases of the with: statement, true.
> 
> <humor> Ouch!  Ignorant of the use cases of the with statement, am I?
> Odd, I use it all the time. </humor>
> 
>> Given only your
>> example of the with: statement, it is hard to fault him for thinking that try:
>> finally: wouldn't suffice.
> 
> <humor> Damn me with faint praise, will you? </humor>
> 
> I'm kinda amazed at the drama my innocent request for the use case
> elicited.  From what I've gotten so far from this thread, for the
> actual example Mr. Steinbach used, the only disadvantage to my counter-
> example using try/finally is that the chdir in the finally part will
> always be executed, even if the chdir in the try part did not
> succeed.  I concede that, and was aware of it when I wrote it.  For
> the simple example given, I did not consider it compelling.

Uhm, well.

My example was:

   with Cleanup as at_cleanup:
       # blah blah
       chdir( somewhere )
       at_cleanup.call( lambda: chdir( original_dir ) )
       # blah blah

It was not intended to compel, rather just to illustrate usage. :-)

And you asked about comparing that with ...

    original_dir = os.getcwd()
    try:
        os.chdir(somewhere)
        # Do other stuff
    finally:
        os.chdir(original_dir)
        # Do other cleanup

.. which does something different, namely, always executing the 
os.chdir(original_dir) or more generally the action-specific cleanup.

The action-specific cleanup might be much more costly than a chdir, and/or, in 
the case where the action failed, incorrect.

In the same number of lines and with fewer keystrokes you could have written 
code that was equivalent to the code I posted and that you wanted to compare 
with, e.g. ...

    original_dir = os.getcwd()
    os.chdir(somewhere)
    try:
        # Do other stuff
    finally:
        os.chdir(original_dir)
        # Do other cleanup

... so given how easy it is to write such an equivalent code snippet, I assumed 
that the different behavior was /not/ intended, that instead, you'd attempted to 
write equivalent code but made a slight error in the translation to lower level 
construct  --  but impossible to say exactly what.

Now you write that you were "aware of [the different behavior] when I wrote it", 
and that just baffles me: why not then, as a basis of sound comparision, write 
the equivalent code shown above, the same number of lines as what you wrote?


>  A more
> complex example, that would have required multiple, nested try/finally
> blocks, would show the advantages of Mr Steinbach's recipe more
> clearly.
> 
> However, I fail to understand his response that I must have meant try/
> else instead, as this, as Mr. Kern pointed out, is invalid syntax.
> Perhaps Mr. Steinbach would like to give an example?

OK.

Assuming that you wanted the chdir to be within a try block (which it was in 
your code), then to get code equivalent to my code, for the purpose of a 
comparision of codes that do the same, you'd have to write something like ...

    original_dir = os.getcwd()
    try:
        os.chdir(somewhere)
    except Whatever:
        # E.g. log it.
        raise
    else:
        try:
            # Do other stuff
        finally:
            os.chdir(original_dir)
            # Do other cleanup

... which would be a more general case.

I've also given this example in response to Robert earlier in the thread. 
Although I haven't tried it I believe it's syntactically valid. If not, then the 
relevant typo should just be fixed. :-)

I have no idea which construct Robert thought was syntactically invalid. I think 
that if he's written that, then it must have been something he thought of.


Cheers & hth.,

- Alf



More information about the Python-list mailing list