[Python-ideas] with ... except

Nick Coghlan ncoghlan at gmail.com
Fri Mar 8 12:43:52 CET 2013


On Fri, Mar 8, 2013 at 8:13 PM, Antoine Pitrou <solipsis at pitrou.net> wrote:
>
> Hello,
>
> A common pattern for me is to write a with statement for resource
> cleanup, but also handle specific errors after that. Right now, this is
> a bit cumbersome:
>
>   try:
>       with open("somefile", "rb)" as f:
>           ...
>   except FileNotFoundError:
>       # do something else, perhaps actually create the file

The main problem with this kind of construct is that it makes the
scope of the exception handler too broad - it's covering the entire
body of the with statement, when you really only want to cover the
creation of the file object:

    try:
        f = open("somefile", "rb")
    except FileNotFoundError:
        # Do something else, perhaps including creating the file
    else:
        with f:
            # This is not covered by the except clause...

Generalising this to context manages with non-trivial __enter__
methods is actually one of the intended use cases for
contextlib.ExitStack (see
http://docs.python.org/dev/library/contextlib#catching-exceptions-from-enter-methods).

> or:
>
>   try:
>       with transaction.commit_on_success():
>           ...
>   except ObjectDoesNotExist:
>       # do something else, perhaps clean up some internal cache

This use case is a bit more reasonable in terms of actually wanting
the except clause to cover the whole body of the with statement, but
trying to lose the extra indentation level suffers from an ambiguity
problem. A full try statement looks like:

    try:
        ...
    except:
        ...
    else:
        ...
    finally:
        ...

The defined semantics of a with statement already include three of
those clauses (try, except, finally). Does the except clause still
fire if the with statement suppresses the exception? With the nested
form, the answer is clearly yes. With the flattened form, the answer
is less obvious. Furthermore, if the with statement allows "except",
does it also allow else and finally? If not, why not?

It's these issues that make me feel this case is more like requests to
merge for + if than it is the past merger of the two forms of try
statemet.

> How about adding syntax sugar for the above, in the form of a with ...
> except clause? It would nicely reduce spurious indentation, as with
> the try / except / finally which, long ago(!), helped reduce
> indentation and typing by removing the need to nest a try / except
> inside a try / finally.

The difference there was that the indentation truly was redundant -
converting between the two forms literally meant dedenting the inner
try/except/else and losing the extra "try:" line. For a long time, the
AST didn't even have a merged try/except/finally construct (eventually
they *were* merged so that source code could be roundtripped through
the AST more reliably). The repeated "try:" was also substantially
more irritating than "try:" following a "with:" header.

It *is* annoying that composing with statements with explicit
exception handling is somewhat clumsy, but I don't think this is the
way to fix it.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia



More information about the Python-ideas mailing list