Какой самый питонический способ условно вернуть функцию

Скажем, у меня есть 2 функции. Я хочу func2 вернуть func1 UNLESS func1 возвращает None, и в этом случае func2 возвращает что-то еще. Есть два способа сделать это, но они оба чувствуют себя немного неправильно.

Я мог бы сказать:

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

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

Но это кажется неправильным, потому что я должен дважды вызвать func1 (n) (а func1 (n) - более крупное вычисление). Чтобы обойти это, я мог бы сказать:

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

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

но это кажется неправильным, потому что я не думаю, что мне нужно будет назначить новую переменную, которая никогда не будет использоваться снова, просто чтобы проверить, вернул ли func1 None.

Есть ли более простой способ сделать это, когда мне не нужно дважды звонить func1, и мне не нужно создавать новую переменную? Если это единственный способ, какой из двух вы бы порекомендовали? В настоящее время я использую его вторым способом (где я устанавливаю foo для возвращаемого func1, чем возвращает foo, если foo == None)

Кроме того, имейте в виду, что в моем реальном коде я вызываю несколько разных функций, и я хочу вернуть первый, который не является None, это просто более простая версия кода, которая задает вопрос.

Ответ 1

Предоставление имени результата вызова func1 относительно дешево, поэтому я бы сделал это, но напишу функцию следующим образом:

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

Ответ 2

Так как None оценивается как False, вы можете сделать:

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

Следует отметить, однако, что это приведет к возврату func2 something_else, если func1(n) возвращает что-либо ложное (0, [] и т.д.)


Для многих функций вы можете использовать next и некоторый генератор выражения:

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)

Ответ 3

Вы определенно не хотите дважды звонить func1, а также быть неэффективными, func1 может иметь побочные эффекты или давать немного другой ответ в зависимости от состояния в то время.

Кроме того, нет необходимости в else после return, когда return вышел из функции.

Пересмотренная версия вашего второго варианта будет:

def func1(n):
    if condition:
        return foo

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

Обратите внимание, что это работает, даже если функция func1 возвращает значение false.

В качестве альтернативы, отметив содержимое func1, вы могли бы сделать:

def func1(n):
    return foo

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

Это зависит от того, каков реальный контент func1.

Ответ 4

Как совершенно другой подход из моего предыдущего ответа, основанный на вашем комментарии к 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