Reputation: 2801
Suppose I have two (or more) functions. One is higher level, processing stuff by calling different other functions. If one of these functions fails (e.g. Math error), I want to "abort" not only that function, but also the ones that called it. In my case I need this to escape an error and avoid having the rest of all calculations done, without quitting the whole process (which would also terminate my GUI). Instead, I want the script to continue running, but back on the upmost level.
This is an abstraction of my original problem:
def levelA(x):
xx = levelB(x=x)
xx *= 2
return xx
def levelB(x):
if x==0: return
y = 10 / x
return y
x = 0
print (levelA(x=x))
Initializing x
with the value 0 would cause a crash in levelB
when 10 is divided by x
. So I first make sure that x
is different from 0. If it's not, the function is aborted by calling return. Now levelA
wants to continue with the doubling of the result of levelB
which, in the case x=0
, is "None" and there we go with another crash.
Of course, what I can do is inserting the line
if xx is None: return
before doing xx *= 2
. But in my real case, there is not just one extra level, but 2 or even 3 and there are many different functions that are called. I want to avoid checking each and every output of the function for errors.
So my question is: Can I somehow go all the way back to the first function call and skip the ones that were in between? Something like a "deep return"?
Upvotes: 3
Views: 315
Reputation: 63
how about try/catch?
def levelA(x):
xx = levelB(x=x)
xx *= 2
return xx
def levelB(x):
if x==0: raise ZeroDivisionError
y = 10 / x
return y
try:
x = 0
print (levelA(x=x))
except ZeroDivisionError:
// error handling or other stuff
Upvotes: 3
Reputation: 152725
Initializing x with the value 0 would cause a crash in levelB when 10 is divided by x. So I first make sure that x is different from 0. If it's not, the function is aborted by calling return.
That's a good summary but you reached the wrong conclusion. You shouldn't return
, you should raise an Exception
. Then you can use a try
, except
clause wherever you want to handle that:
def levelA(x):
xx = levelB(x=x)
xx *= 2
return xx
def levelB(x):
if x==0: raise ValueError
y = 10 / x
return y
x = 0
try:
print(levelA(x=x))
except ValueError:
print('x was invalid! Wanna try again?')
Even better would be to just do the division and catch the Exception raised there:
def levelA(x):
xx = levelB(x=x)
xx *= 2
return xx
def levelB(x):
y = 10 / x
return y
x = 0
try:
print(levelA(x=x))
except ZeroDivisionError:
print('x was invalid! Wanna try again?')
Upvotes: 1
Reputation: 37103
Exceptions were invented to handle the situation you describe. So, for example:
In [72]: def f1(x):
...: return f2(x)
...:
In [73]: def f2(x):
...: return f3(x)
...:
In [74]: def f3(x):
...: if x > 0:
...: return x
...: else:
...: raise ValueError("f3 called with negative argument")
...:
In [75]: try:
...: print(f1(-2))
...: except ValueError as e:
...: print(e)
...:
f3 called with negative argument
Upvotes: 3