A "scopeguard" for Python

Steve Howell showell30 at yahoo.com
Fri Mar 5 11:49:41 EST 2010


On Mar 4, 5:04 pm, Robert Kern <robert.k... at gmail.com> wrote:
> On 2010-03-04 15:19 PM, Mike Kent wrote:
>
>
>
> > On Mar 3, 12:00 pm, Robert Kern<robert.k... at gmail.com>  wrote:
> >> On 2010-03-03 09:39 AM, Mike Kent wrote:
>
> >>> What's the compelling use case for this vs. a simple try/finally?
>
> >>>      original_dir = os.getcwd()
> >>>      try:
> >>>          os.chdir(somewhere)
> >>>          # Do other stuff
> >>>      finally:
> >>>          os.chdir(original_dir)
> >>>          # Do other cleanup
>
> >> A custom-written context manager looks nicer and can be more readable.
>
> >> from contextlib import contextmanager
> >> import os
>
> >> @contextmanager
> >> def pushd(path):
> >>       original_dir = os.getcwd()
> >>       os.chdir(path)
> >>       try:
> >>           yield
> >>       finally:
> >>           os.chdir(original_dir)
>
> >> with pushd(somewhere):
> >>       ...
>
> > Robert, I like the way you think.  That's a perfect name for that
> > context manager!  However, you can clear one thing up for me... isn't
> > the inner try/finally superfluous?  My understanding was that there
> > was an implicit try/finally already done which will insure that
> > everything after the yield statement was always executed.
>
> No, the try: finally: is not implicit. See the source for
> contextlib.GeneratorContextManager. When __exit__() gets an exception from the
> with: block, it will push it into the generator using its .throw() method. This
> raises the exception inside the generator at the yield statement.
>

See also:

http://docs.python.org/library/contextlib.html

The closing() helper can be used to automatically call thing.close()
even after an exception.

If you do not use the closing() helper and take on the responsibility
yourself of doing try/finally within your generator, I think you still
gain some overall simplicity:

  1) You don't need to do try/finally in your with blocks, of course.
  2) The generator itself probably reads more straightforwardly then a
hand-coded class with __enter__ and __exit__.

For point #2, I think there are probably different aesthetics.
Generators are more concise, but they are also a bit mind-bending.



More information about the Python-list mailing list