Search code examples
pythonfunctionreturn

"Deep return" all the way back to first function call


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"?


Solution

  • 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