[Python-Dev] Chaining try statements: eltry?

Thomas Lotze thomas at thomas-lotze.de
Wed Jul 6 20:07:45 CEST 2005


Hi,

this is my first message to this list, so let me say hello first.

I want to ask what you think about introducing a keyword 'eltry' which
would be the counterpart of 'elif' for try statements. This had been
suggested before on python-list a couple of years ago by Jonathan
Gardner, but nothing (that I could find) seems to have come of it.


Starting from PEP 341, the try statement might be extended to

try_stmt: 'try' ':' suite
          (
            (except_clause ':' suite)+
            (
              'eltry' ':' suite
              (except_clause ':' suite)+
            )*
            ['else' ':' suite]
            ['finally' ':' suite]
          |
            'finally' ':' suite
          )

where lines 4 through 7 would be an addition to the definition given in
the PEP. Admittedly, this looks somewhat complex, but I don't think it
actually is. (And while an new keyword always means potentially breaking
code, 'eltry' doesn't seem to me a likely identifier chosen by
programmers - YMMV.)


This extension would be useful whenever a suite of statements is to be
terminated as soon as one of them raises an exception, and the
programmer is interested in handling those individually. Without 'eltry'
the choices are:

- Stack conventional try statements, each inside the else clause of
  the one before. This causes deep nesting, and while typical nesting
  depths won't be as great as they might become with stacked if
  statements, it is annoying and ugly IMO.

- Run all statements at once and put all exception handlers outside the
  suite. This yields code that is harder to read than necessary as some
  handlers will be written far from the statement where the exception
  they handle is raised. Moreover, if more than one statement may raise
  a particular exception, some effort is required to find out which one
  did it if there is only one handler for that exception.

- Break up the suite into separate try statements. While this may result
  in well readable code if each handler breaks out of the block 
  containing the whole run of try statements, it requires some mechanism
  (such as a wrapper try statement or a separate function that may quit
  anytime) if exiting the current block is not desired.

- Something else, in which case I'm looking forward to learning
  something new about Python ;o)


An example would be a filter chain:

def use_eltry(data):
    # decode as far as possible
    try:
        data = foo_decode(data)
    except ValueError:
        print "Data seems not to be foo encoded."
    eltry:
        data = bar_decode(data)
    except ValueError:
        print "Foo decoded data seems not to be bar encoded."
    eltry:
        data = baz_decode(data)
    except ValueError:
        print "FooBar decoded data seems not to be baz encoded."

    # whatever data is by now, do something with it
    do_something(data)


def use_stacking(data):
    # decode as far as possible
    try:
        data = foo_decode(data)
    except ValueError:
        print "Data seems not to be foo encoded."
    else:
        try:
            data = bar_decode(data)
        except ValueError:
            print "Foo decoded data seems not to be bar encoded."
        else:
            try:
                data = baz_decode(data)
            except ValueError:
                print "FooBar decoded data seems not to be baz encoded."

    # whatever data is by now, do something with it
    do_something(data)


def use_single_handler(data):
    # decode as far as possible
    try:
        data = foo_decode(data)
        data = bar_decode(data)
        data = baz_decode(data)
    except ValueError:
        print "Data could not be decoded, can't tell you why easily."

    # whatever data is by now, do something with it
    do_something(data)


def use_custom_exception(data):
    # decode as far as possible
    try:
        try:
            data = foo_decode(data)
        except ValueError:
            print "Data seems not to be foo encoded."
            raise

        try:
            data = bar_decode(data)
        except ValueError:
            print "Foo decoded data seems not to be bar encoded."
            raise

        try:
            data = baz_decode(data)
        except ValueError:
            print "FooBar decoded data seems not to be baz encoded."
            raise
    except ValueError:
        pass

    # whatever data is by now, do something with it
    do_something(data)


def use_function(data):
    # decode as far as possible
    def helper():
        try:
            data = foo_decode(data)
        except ValueError:
            print "Data seems not to be foo encoded."
            return

        try:
            data = bar_decode(data)
        except ValueError:
            print "Foo decoded data seems not to be bar encoded."
            return

        try:
            data = baz_decode(data)
        except ValueError:
            print "FooBar decoded data seems not to be baz encoded."
            return

    helper()

    # whatever data is by now, do something with it
    do_something(data)


Does this seem contrived? (Obviously, I don't think so.) It would be
nice to hear your opinions and, if you don't agree with the proposal,
learn what is bad about it.

-- 

Viele Grüße,
Thomas


More information about the Python-Dev mailing list