4

I have this kind of code:

try:
    return make_success_result()
except FirstException:
    handle_first_exception()
    return make_error_result()
except SecondException:
    handle_second_exception()
    return make_error_result()

And I'm wondering is there any way I can achieve this:

try:
    # do something
except Error1:
    # do Error1 specific handling
except Error2:
    # do Error2 specific handling
else:
    # do this if there was no exception
????:
    # ALSO do this if there was ANY of the listed exceptions (e.g. some common error handling)

So the code is executed in one of following sequences:

try > else > finally
try > except > ???? > finally

EDIT: my point here is that ???? block should execute right after ANY of the except blocks, meaning that it's an addition to error handling, not a substitution.

3Gee
  • 1,094
  • 2
  • 14
  • 23

4 Answers4

5

What I would do in that case is to set a boolean when you get an exception, like so:

got_exception = False
try:
    # do something
except Error1:
    # do Error1 specific handling
    got_exception = True
except Error2:
    # do Error2 specific handling
    got_exception = True
else:
    # If there was no exception
finally:
    if got_exception:
        # ALSO do this if there was ANY exception (e.g. some common error handling)

This should fit your needs, which is IMO the cleanest way of combining all of the solutions which have been presented into the most readable code structure that's going to be the easiest to debug.

Matt Taylor
  • 3,360
  • 1
  • 20
  • 34
  • There is already a built in solution in python to do this, see my comment – Martin Hallén Nov 11 '15 at 08:49
  • If you don't catch `except Exception:` (or just `except:`), then any exception not explicitly caught will escape after the `finally:` clause, and the `got_exception` variable will not be set... – thebjorn Nov 11 '15 at 09:20
  • @thebjorn As far as I'm aware, that's not true, if an exception not explicitly caught occurs, then it will run the `try/finally` blocks, then throw the error. Only if you do something which swallows _everything_ in the `finally` will a generic `Exception` slip through – Matt Taylor Nov 11 '15 at 09:28
  • @MattTaylor the question is whether `if got_exception:` should be executed if something other than `Error1` or `Error2` is raised. As your code is now, it will not. The OP says that it should execute when ANY exception is raised (although I guess it's open for interpretation if that means just any of the one's listed..) – thebjorn Nov 11 '15 at 09:33
  • @thebjorn I agree, in my interpretation that's there for cleanup of the exceptions which were expected - not just to trap any exception which might happen to occur. – Matt Taylor Nov 11 '15 at 09:34
  • @thebjorn agree to disagree? =) – Matt Taylor Nov 11 '15 at 09:34
  • That's my bad, I meant any of the listed exceptions – 3Gee Nov 11 '15 at 09:35
1

You can actually do this:

try:
    print 'try'
    # 1/0
    # {}[1]
    # {}.a
except AttributeError, KeyError:  # only handle these exceptions..
    try:
        raise                     # re-raise the exception so we can add a finally-clause executing iff there was an exception.
    except AttributeError:
        print 'attrerr'
        # raise ...               # any raises here will also execute 'common'
    except KeyError:
        print 'keyerror'
    finally:                      # update 0: you wanted the common code after the exceptions..
        print "common"

else:
    print 'no exception'

but it is horrid and I would not suggest that you do without copious amounts of comments describing why..

UPDATE: you don't need to catch anything but the interesting exceptions in the inner try-block. Code updated.

UPDATE2: per OP's clarification, common should just be executed when an interesting exception is thrown. Code updated. @MattTaylor's version is definitely the way to go ;-)

thebjorn
  • 26,297
  • 11
  • 96
  • 138
  • Which IMO, makes my answer the cleanest solution to the problem. You're right, it doesn't read very well. I've updated my answer to include the use of the `else:` statement. – Matt Taylor Nov 11 '15 at 09:15
  • thebjorn, yes, that's way too complicated, thus so far Matt Taylor's answer is the cleanest indeed – 3Gee Nov 11 '15 at 09:18
0

Yes, exception handling in python includes both an else and a finally clause. You can do this:

try:
    # do something
except Error1:
    # do Error1 specific handling
except Error2:
    # do Error2 specific handling
else:
    # do this if there was no exception
finally:
    # Do this in any case!

The python docs mention these blocks, even though it doesn't show the full example you need.


EDIT: I see that you do not ask specifically for the clean-up in the general case. Python docs put it this way:

The try statement has another optional clause which is intended to define clean-up actions that must be executed under all circumstances.

Note that the finally will run whether there was an exception or not. Combined with the else block, you should still be able to do what you want.

Martin Hallén
  • 1,492
  • 1
  • 12
  • 27
  • `finally` is executed whether there is an exception or not. @MedhatGayed's solution is the correct one. – thebjorn Nov 11 '15 at 08:53
  • @thebjorn: You're right. I edited the answer in the moment you wrote the comment. I do still think you can use this if you just make sure things go in the correct block – Martin Hallén Nov 11 '15 at 08:58
  • @mart0903 if you think so, then you should edit your answer to show which parts need to go in which block... (I think an uncaught exception will escape after the finally clause is called no matter how you structure it..) – thebjorn Nov 11 '15 at 09:03
  • I'm aware of `finally`, but it's not suitable for me, because it will be executed under all circumstances. And basically the only solution solution working so far is adding flag + using finally as @MattTaylor suggested, but I wonder if there is a cleaner way without using flags – 3Gee Nov 11 '15 at 09:09
0

You could trap all errors and check for its type in the error handling code like this:

try:
    # do something
except Exception as e:
    if isinstance(e, Error1):
        # do Error1 specific handling
    elif isinstance(e, Error2):
        # do Error2 specific handling
    else:
        # do non-Error1/Error2 handling
    # ALSO do this if there was ANY exception (e.g. some common error handling)
else:
    # do this if there was no exception
Rob
  • 3,418
  • 1
  • 19
  • 27
  • @thebjorn That is always the case, even when you use a finally clause. If you get errors in your error handling code, all is lost. – Rob Nov 11 '15 at 09:39