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