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.