Когда использовать 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]

Ответ 1

Я добавлю свой комментарий к ответу.

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

>>> 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.

Ответ 4

elif немного эффективнее, и это вполне логично: при if программа должна каждый раз оценивать каждое логическое выражение. В elif, хотя это не всегда так. Однако в вашем примере это улучшение было бы очень, очень маленьким, возможно, незаметным, так как оценка 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 < 0 (дешевый и простой), и только если это не так, будет ли он оценивать более сложное выражение (кстати, этот код не имеет большого смысла, это просто случайный пример)

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

Ответ 5

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

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

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

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 $10 to enter our draw for a random discount'

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

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

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