2

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.

2

4 Answers 4

4

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>
Sign up to request clarification or add additional context in comments.

3 Comments

Glad it helped. Please remember to upvote useful answers and, when you can, select the one that worked best for you as your accepted answer.
you could just use range instead of a while and also stick the calculations in a dict
@PadraicCunningham That is a much better solution. I re-edited to use a list of functions and a for loop.
1

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.

Comments

0

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.

Comments

0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.