Reputation: 758
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
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
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
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
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