когда использовать if vs elif в python

Если у меня есть функция с несколькими условные операторы, где каждая ветвь выполняется возврат из функции. Должен ли я использовать несколько операторов if или if/elif/else? Например, скажем у меня есть функция:

def example(x):
    if x > 0:
        return 'positive'
    if x < 0:
        return 'negative'
    return 'zero'

лучше написать:

def example(x):
    if x > 0:
        return 'positive'
    elif x < 0:
        return 'negative'
    else:
        return 'zero'

оба имеют одинаковый результат, но является ли один более эффективным или считается более идиоматичным, чем другой?

Edit:

несколько человек сказали, что в первый пример оба оператора if всегда оцениваются, что, похоже, не так для меня

например, если я запускаю код:

l = [1,2,3]

def test(a):
    if a > 0:
        return a
    if a > 2:
        l.append(4)

test(5)

l все равно будет равен [1,2,3]

5 ответов


я расширю свой комментарий до ответа.

в случае, если все случаи возвращаются, они действительно эквивалентны. То, что становится важным при выборе между ними, - это то, что более читаемо.

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

скажем, например, кто-то решает, что есть другой случай:

def example(x):
    if x > 0:
        return 'positive'
    if x == -15:
        print("special case!")
    if x < 0:
        return 'negative'
    return 'zero'

внезапно появляется потенциальная ошибка, если пользователь намеревался, чтобы этот случай был взаимоисключающим (очевидно, это не имеет большого смысла, учитывая пример, но потенциально может в более реалистичном случае). Эта двусмысленность удаляется, если elifS используются, и поведение становится видимым для человека, добавляющего код на уровне, на который они, вероятно, будут смотреть, когда они добавляют он.

если бы я столкнулся с вашим первым примером кода, я бы, вероятно, предположил, что выбор использовать ifС, а не elifs подразумевалось, что случаи были не взаимоисключающие, и поэтому такие вещи, как изменение значения x может использоваться для изменения, который ifs execute (очевидно, в этом случае намерение является очевидным и взаимоисключающим, но опять же, мы говорим о менее очевидных случаях-и последовательность хороша, поэтому даже в простом примере, когда она очевидно, лучше придерживаться одного пути).


В некоторых случаях elif требуется для правильной семантики. Это тот случай, когда условия не являются взаимоисключающими:

if x == 0:   result = 0
elif y == 0: result = None
else:        result = x / y

в некоторых случаях это эффективно, потому что интерпретатору не нужно проверять все условия, что имеет место в вашем примере. Если x отрицательно, то почему вы проверяете положительный случай? Ан elif в этом случае также делает код более читаемым, поскольку он ясно показывает, что будет выполнена только одна ветвь.


проверить это, чтобы понять разницу:

>>> a = 2
>>> if a > 1: a = a+1
...
>>> if a > 2: a = a+1
...
>>> a
4

и

>>> a = 2
>>> if a > 1: a = a+1
... elif a > 2: a = a+1
...
>>> a
3

первый случай эквивалентен двум различным ifС пустым else заявления (или представить else: pass); во втором случае elif часть первая if заявление.


elif немного эффективнее, и это вполне логично: с ifs программа должна оценивать каждое логическое выражение каждый раз. В elifs хотя, это не всегда так. Однако в вашем примере это улучшение было бы очень, очень небольшим, вероятно, незаметным, как оценка x > 0 одна из самых дешевых операций.

при работе с elifэто также хорошая идея, чтобы думать о лучшем порядке. Рассмотрим следующий пример:

if (x-3)**3+(x+1)**2-6*x+4 > 0:
    #do something 1
elif x < 0:
    #do something 2

здесь программа должна будет оценивать уродливое выражение каждый раз! Однако, если мы изменим порядок:

if x < 0:
   #do something 2
elif (x-3)**3+(x+1)**2-6*x+4 > 0:
   #do something 1

теперь программа сначала проверит, если x

кроме того, что perreal сказал.


в общем (например, ваш пример), вы всегда будете использовать if..elif лестница, чтобы явно показать, что условия являются взаимоисключающими. Это предотвращает двусмысленность, ошибки и т. д.

единственная причина, по которой я могу думать, что вы никогда не могли бы использовать elif и использовать if вместо этого было бы, если бы действия из тела предыдущего if заявление (или утверждения), возможно, изменили условие, чтобы потенциально сделать его более не взаимоисключающим. Так что не длиннее действительно лестница, просто отдельные сцепленные if(..elif..else) блоки. (Оставьте пустую строку между отдельными блоками, для хорошего стиля, и чтобы кто-то случайно не подумал, что это должно быть elif и "исправление" его)

вот надуманный пример, просто чтобы доказать свою точку зрения:

if total_cost>=10:
    if give_shopper_a_random_discount():
        print 'You have won a discount'
        total_cost -= discount
    candidate_prime = True

if total_cost<10:
    print 'Spend more than  to enter our draw for a random discount'

вы можете видеть, что можно поразить оба условия, если первый if-block применяет скидку, поэтому мы также выполняем второй, который печатает сообщение, которое будет запутанный, так как наш первоначальный итог был >=10.

An elif здесь предотвратил бы этот сценарий. Но могут быть и другие сценарии, в которых мы хотим запустить второй блок, даже для этого сценария.

if total_cost<10:
    <some other action we should always take regardless of original undiscounted total_cost>