diffracteD
diffracteD

Reputation: 758

multiple exception handler in python

I'm writing code that has to deal with a lot of IndexError exceptions.
So, I used a try except block:

try:
    <do some level_1 calculations>
except IndexError:
    <change to level_2 calculations>  

But, what if my exception-handler again raises another IndexError?
How can I safely put another IndexError exception with this code structure so that, if the level_2 calculation again gets caught in an IndexError, then the code runs "level_3 calculations" as an exception again and so on.

Upvotes: 2

Views: 141

Answers (4)

SuperBiasedMan
SuperBiasedMan

Reputation: 9969

You can just nest try except blocks, like so:

try:
    <do some level_1 calculations>
except IndexError:
    try:
        <change to level_2 calculations>
    except IndexError:
        try:
            <change to level_3 calculations>
        except IndexError:
            <change to level_4 calculations>

But that would look messy and can cause trouble if you mess up formatting, it would probably be better to use a list of functions that you loop over attempting different calculations until all have failed and then you handle the exception some other way.

calulators = [
                 level_1_calculation_function,
                 level_2_calculation_function,
                 level_3_calculation_function,
             ]

for attempt in range(len(calculators)):
    try:
        result = calculators[attempt]
        break #If we've reached here, the calculation was successful
    except IndexError:
        attempt += 1
else:
    #If none of the functions worked and broke out of the loop, we execute this.
    <handle_exception>

Upvotes: 4

Mp0int
Mp0int

Reputation: 18727

Nesting the try-except block is the right way to go. Because possible exceptions occurs outside of your try block.

There is one another way, but that is not something that I will advice you if you do not have very specific reasons to use it. It makes things look a bit more messy and requires you to use default try-except blocks nested within each other with a final try-except block to cover them all!

class FirstLevelFuncException(Exception):
    pass

class SecondLevelFuncException(Exception):
    pass

class ThirdLevelFuncException(Exception):
    pass

try: 
# This is the base try block that will cover your code and catch Function Level based exceptions
    try:
        <do some level_1 calculations>
    except IndexError:
        try:
            <change to level_2 calculations>
        except IndexError:
            try:
                <change to level_3 calculations>
            except IndexError:
                <change to level_4 calculations>
            else:
                raise SecondLevelFuncException()
        else:
            raise FirstLevelFuncException()
    else:
        pass
except Exception as e:
    print e

That will try to execute functions in given order and when it completes a step without error, it will raise exception related to previous level, so you can keep track of the execution.

But as I said, that is not a good and proper way to go unless you have very specific needs.

Upvotes: 0

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

Put the calculations/funcs in a list:

from random import choice
from operator import mul, add

funcs = [mul, add]

for f in funcs:
    try:
        i = l[choice([1, 2, 3])]
        calc = f(i[0], i[1])
        print(calc)
        break # break if you want the first successful calc to be the last
    except IndexError as e:
        print(e)
        continue

If you run the code you will see random indexError's being caught.

Upvotes: 1

Eugene S
Eugene S

Reputation: 6910

Generally, when you are writing code you should be aware of what can happen at any stage and you should place your exception handlers accordingly.

Saying that, if you are performing a series of operations where there are multiple places that can cause a specific exception, you can enclose the whole block into a single exception handler of an appropriate type. In other cases, when you require a different behavior as a result of some other exceptions, define separate handlers.

Both ways are correct logically and rather a question of design.

Upvotes: 0

Related Questions