2

I have a couple of functions that return either a number or None. I want my wrapper function to return the first result that is not None. Is there any other way to do this than as following?

def func1():
    return None
def func2():
    return 3
def func3():
    return None

def wrapper():
    result = func1()
    if result is not None:
        return result
    result = func2()
    if result is not None:
        return result
    result = func3()
    if result is not None:
        return result

I am aware of return func1() or alternative; which returns the outcome of func1() unless it is None, then alternative is returned. In the most optimal situation I do something like (pseudo code):

return func1() or continue
return func2() or continue
return func3() or continue
3
  • 2
    What about return func1() or func2() or func3() ? Commented Mar 10, 2020 at 16:07
  • Hmm I like that better already! What if there's fifty functions though? Commented Mar 10, 2020 at 16:09
  • @jorijnsmit: In that case you would have a real loop iterating over a list of functions, with a single break. Commented Mar 10, 2020 at 16:10

4 Answers 4

4

You need a loop which will return the first non-None value it finds.

def wrapper():
    for f in [func1, func2, func3]:
        result = f()
        if result is not None:
            return result

If every function returns None, wrapper will as well by reaching the end of the body without an explicit return.

Shortened slightly in Python 3.8 or later,

def wrapper():
    for f in [func1, func2, func3]:
        if (result := f()) is not None:
            return result

You can also make use of the any function:

def wrapper():
    if any((result := f()) is not None for f in [func1, func2, func3]):
        return result

(I prefer the explicit loop; YMMV.)

Sign up to request clarification or add additional context in comments.

Comments

2

If there's only three functions, and you don't care about distinguishing None from other falsey values, you can use

return func1() or func2() or func3()

If there are lots of functions, or if you want to be more discriminating about the return values, then you could put them all in a list and use

return next(x for x in (f() for f in funcs) if x is not None)

If you want to cope with all of your functions returning None, you can add a default value for next, e.g.

return next((x for x in (f() for f in funcs) if x is not None), None)

Comments

1

You could combine map, filter and next:

def func1():
    print("executed func1()")
    return None
def func2():
    print("executed func2()")
    return 3
def func3():
    print("executed func3()")
    return None

functions = (func1,func2,func3)
call      = lambda f:f()
result    = next(filter(None,map(call,functions)),None)

print("result:",result)

output:

executed func1()
executed func2()
result 3

func 3 is not executed

If your functions have parameters you can still use this approach by building the list of functions with lambdas:

def func1(p1):
    print(f"executed func1({p1})")
    return None
def func2(p2a,p2b):
    print(f"executed func2{(p2a,p2b)}")
    return 3
def func3(p3):
    print(f"executed func3({p3})")
    return None

functions = [
               lambda: func1(10),
               lambda: func2("X",99),
               lambda: func3(3.5)
            ]
call      = lambda f:f()
result    = next(filter(None,map(call,functions)),None)

print(result)

output:

executed func1(10)
executed func2('X', 99)
3

1 Comment

Thanks for that lambda construction, that's really useful to be able to pass different arguments!
0

You can do this:

def wrapper():
    functions = [func1, func2, func3]
    return next(filter(lambda result: result is not None,
                       f() for f in functions),
                None)

It returns None if all the functions return None.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.