4

Say I have 2 functions. I want func2 to return func1 UNLESS func1 returns None, in which case func2 returns something else. There are two ways that I could do this, but they both feel slightly wrong.

I could say:

def func1(n):
    if (condition):
        return foo

def func2(n):
    if func1(n) is not None:
        return func1(n)
    else:
        return something_else

But this feels wrong because I have to call func1(n) twice (and func1(n) is a larger computation). To get around that, I could say:

def func1(n):
    if (condition):
        return foo

def func2(n):
    foo = func1(n)
    if foo is not None:
        return foo
    else:
        return something_else

but this feels wrong because I don't think I should have to assign a new variable that will never get used again, just to check if func1 returned None.

Is there an easier way to do this where I don't have to call func1 twice and I don't have to create a new variable? If this is the only way, which of the two would you recommend? I currently have it using the second way (Where I set foo to what func1 returned, than return foo unless foo == None)

Also, keep in mind that in my real code, I call several different functions, and I want to return the first one that is not None, this is just a simpler version of code that gets the question across.

DJMcMayhem
  • 7,285
  • 4
  • 41
  • 61
  • 1
    You should use `is` and `is not` instead of `==` and `!=`, for singletons like `None`. So say the docs. http://stackoverflow.com/questions/2209755/python-operation-vs-is-not – TheSoundDefense Jul 15 '14 at 19:00
  • Please don't use `== True`; `if condition:` is enough and less prone to errors (as comparisons chain, you're likely to produce the wrong expression if you added other comparisons). – Martijn Pieters Jul 15 '14 at 19:01
  • Also, if you're checking against a type use `isinstance` – blakev Jul 15 '14 at 19:01
  • Okay, keep in mind that this is not exactly my code, but simpler code I made to show what I was trying to do. – DJMcMayhem Jul 15 '14 at 19:06

4 Answers4

9

Since None evaluates to False, you could do:

def func2(n):
    return func1(n) or something_else

It should be noted however that this will cause func2 to return something_else if func1(n) returns anything falsey (0, [], etc.)


For many functions, you could use next and some generator expressions:

def myfunc(n):
    vals = (f(n) for f in (func1, func2, func3...))
    return next((v for v in vals if v is not None), something_else)
  • 1
    If you need to return something falsey from `func1(n)`, do `ret = func1(n); return ret if ret is not None else something_else` – dano Jul 15 '14 at 19:11
  • Hm, maybe I should have specified this in the question, but I have many different functions, and I want to return the first one that isn't None. I guess I could do `return func1(n) or func2(n) or func3(n) or something_else` – DJMcMayhem Jul 15 '14 at 19:11
6

Giving a name to the result of calling func1 is relatively cheap, so I'd do that, but write the function like this:

def func2(n):
    ret = func1(n)
    return ret if ret is not None else something_else
martineau
  • 119,623
  • 25
  • 170
  • 301
1

You definitely don't want to call func1 twice - as well as being inefficient, func1 may have side effects or produce a slightly different answer depending on the state at the time.

Also, there is no need for the else after a return as the return exited the function.

A revised version of your second option would be:

def func1(n):
    if condition:
        return foo

def func2(n):
    foo = func1(n)
    if foo is None:
        return something_else
    return foo

Note that this works even if 'func1' returns a falsey value.

Alternatively, noting the content of func1, could you do:

def func1(n):
    return foo

def func2(n):
    foo = func1(n)
    if condition:
        return foo
    return something_else

It depends on what the real content of func1 actually is.

neil
  • 3,387
  • 1
  • 14
  • 11
  • I am aware that the else is unnecessary. Also, your revision is basically what my code is now, I am just wondering if it's absolutely needed to create a variable foo. Also, the content of func1 is far too complicated to add the `condition` into func2, especially seeing as how the condition of func1 calls other functions, and returns the first of *those* functions that doesn't return None. – DJMcMayhem Jul 15 '14 at 19:22
  • 1
    I can't think of any way to avoid creating the variable foo if the restrictions of iCodez's answer are a problem. – neil Jul 15 '14 at 19:29
1

As a completely different take from my previous answer, based on your comment to iCodez:

def func1(n):
    return ham

def func2(n):
    return jam

def func3(n):
    return spam

def mainfunc(n):
    for f in (func1, func2, func3):
        foo = f(n)
        if foo is not None:
            return foo
neil
  • 3,387
  • 1
  • 14
  • 11