avoiding nested try/excepts

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steven Bethard

    #1

    avoiding nested try/excepts

    So I have code that looks something like this:

    def f(xs):
    for x in xs:
    y = g(x) # can raise exception AnException
    for z in h(y):
    k(z) # can raise a variety of exceptions

    Now, if g(x) raises AnException, I want to log something and skip the
    inner loop (but continue with the outer loop). If k(z) raises an
    exception, I want to log something and then re-raise the exception to
    exit all the way out of f. Currently I do something like:

    def f(xs):
    for x in xs:
    try:
    y = g(x)
    for z in h(y):
    k(z)
    except AnException, e:
    log(x, e)
    except:
    log(x)
    raise

    I've heard before that it's generally a good idea to try to localize
    your try-except blocks as much as possible. This would lead me to do
    something like:

    def f(xs):
    for x in xs:
    try:
    y = g(x)
    except AnException, e:
    log(x, e)
    else:
    for z in h(y):
    try:
    k(z)
    except:
    log(x)
    raise

    but now I have another level of nesting and things get kinda hard for me
    to read. So I have two questions:

    (1) Should I really worry about localizing try-except blocks? and, if so
    (2) Is there a cleaner way to do this kind of thing?

    Note that I can't edit the g or k functions, so I can't move the
    try-except blocks inside.

    Thanks,

    Steve
  • Andrew Clover

    #2
    Re: avoiding nested try/excepts

    Steven Bethard <steven.bethard @gmail.com> wrote:
    [color=blue]
    > except:
    > log(x)
    > raise[/color]

    (Of course 'except:' is rarely a good idea! You probably want to
    exclude at least MemoryError - as log() might then fail - and possibly
    also KeyboardInterru pt, SystemExit depending on what you're doing.)
    [color=blue]
    > but now I have another level of nesting and things get kinda hard for me
    > to read.[/color]

    I find it fine - I prefer it to the shorter version as it's clearer
    where AnException is expected to be raised.

    In general, localising exception handling is a good move, and I'd
    personally do so in the case of your example. If g() is the only
    method that can possibly raise AnException the shorter version is
    safe, but otherwise botched exception handling can be a real pain to
    track down.

    If you find the nesting level a bit much you could always use fewer
    whitespaces. :-)

    --
    Andrew Clover
    mailto:and@doxd esk.com

    Comment

    • Peter Otten

      #3
      Re: avoiding nested try/excepts

      Steven Bethard wrote:
      [color=blue]
      > (1) Should I really worry about localizing try-except blocks? and, if so[/color]

      Not when the error-handling doesn't take advantage of the greater locality.
      [color=blue]
      > (2) Is there a cleaner way to do this kind of thing?[/color]

      I've always thought that catching an exception was the clean way that
      replaces dealing with functions returning error codes.
      [color=blue]
      > Note that I can't edit the g or k functions, so I can't move the
      > try-except blocks inside.[/color]

      If you cannot modify, you can still wrap them:
      [color=blue][color=green][color=darkred]
      >>> def catch(*exceptio ns):[/color][/color][/color]
      .... def make_catcher(f) :
      .... def catcher(*args):
      .... try:
      .... return f(*args)
      .... except exceptions:
      .... print "caught it"
      .... return catcher
      .... return make_catcher
      ....[color=blue][color=green][color=darkred]
      >>> @catch(ZeroDivi sionError)[/color][/color][/color]
      .... def f(a, b): return a / b
      ....[color=blue][color=green][color=darkred]
      >>> f(1, 2)[/color][/color][/color]
      0[color=blue][color=green][color=darkred]
      >>> f(1, 0)[/color][/color][/color]
      caught it[color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]

      You may guess at what line in the above it dawned on me that you'd be better
      off with individual wrappers than a generalized decorator...

      Peter


      Comment

      • Steven Bethard

        #4
        Re: avoiding nested try/excepts

        Andrew Clover wrote:[color=blue]
        > Steven Bethard <steven.bethard @gmail.com> wrote:
        >[color=green]
        >> except:
        >> log(x)
        >> raise[/color]
        >
        >
        > (Of course 'except:' is rarely a good idea! You probably want to
        > exclude at least MemoryError - as log() might then fail - and possibly
        > also KeyboardInterru pt, SystemExit depending on what you're doing.)[/color]

        So what's the idiom for catching all exceptions *except*
        MemoryError/KeyboardInterru pt/SystemExit? Too bad we won't get our new
        Exceptions hierarchy until Python 3000...

        Steve

        Comment

        Working...