Есть ли в Python троичный условный оператор? - PullRequest
5237 голосов
/ 27 декабря 2008

Если в Python нет тернарного условного оператора, можно ли имитировать оператор с использованием других языковых конструкций?

Ответы [ 21 ]

6186 голосов
/ 27 декабря 2008

Да, добавлено в версии 2.5. Синтаксис выражения:

a if condition else b

Сначала condition оценивается, затем точно один из a или b оценивается и возвращается на основе логического значения condition. Если condition оценивается как True, тогда a оценивается и возвращается, но b игнорируется, или же когда b оценивается и возвращается, но a игнорируется.

Это допускает короткое замыкание, потому что когда condition истинно, только a оценивается, а b вообще не оценивается, но когда condition ложно, только b оценивается и a не оценивается вообще.

Например:

>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'

Обратите внимание, что условные выражения - это выражение , а не выражение . Это означает, что вы не можете использовать операторы присваивания или pass или другие операторы в условном выражении :

>>> pass if False else x = 3
  File "<stdin>", line 1
    pass if False else x = 3
          ^
SyntaxError: invalid syntax

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

x = a if True else b

Думайте об условном выражении как о переключении между двумя значениями. Это очень полезно, когда вы находитесь в ситуации «одного значения или другого», но больше ничего не делает.

Если вам нужно использовать операторы, вы должны использовать обычный if оператор вместо условного выражения .


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

  • Порядок аргументов отличается от порядка классического троичного оператора condition ? a : b из многих других языков (таких как C, C ++, Go, Perl, Ruby, Java, Javascript и т. Д.), Что может привести к ошибкам когда люди, незнакомые с «удивительным» поведением Python, используют его (они могут изменить порядок аргументов).
  • Некоторые считают его "громоздким", поскольку он идет вразрез с нормальным потоком мыслей (сначала думая о состоянии, а затем о последствиях).
  • Стилистические причины. (Хотя «inline if» может быть действительно полезным и сделать ваш сценарий более кратким, это действительно усложнит ваш код)

Если у вас возникают проблемы с запоминанием порядка, помните, что когда вы читаете вслух, вы (почти) говорите, что имеете в виду. Например, x = 4 if b > 8 else 9 читается вслух как x will be 4 if b is greater than 8 otherwise 9.

Официальная документация:

683 голосов
/ 22 января 2009

Вы можете индексировать в кортеж:

(falseValue, trueValue)[test]

test необходимо вернуть True или False .
Может быть безопаснее всегда реализовывать это как:

(falseValue, trueValue)[test == True]

или вы можете использовать встроенный bool(), чтобы обеспечить логическое значение:

(falseValue, trueValue)[bool(<expression>)]
286 голосов
/ 27 декабря 2008

Для версий до 2.5 есть хитрость:

[expression] and [on_true] or [on_false]

Это может дать неправильные результаты, когда on_true имеет ложное логическое значение. 1
Хотя оно имеет преимущество в оценке выражений слева направо, что на мой взгляд более понятно.

1. Есть ли эквивалент троичного оператора C??:?

196 голосов
/ 27 мая 2010

<i><expression 1></i> <b>if</b> <i><condition></i> <b>else</b> <i><expression 2></i>

a = 1
b = 2

1 if a > b else -1 
# Output is -1

1 if a > b else -1 if a < b else 0
# Output is -1
124 голосов
/ 27 декабря 2008

С документация :

Условные выражения (иногда называемые «троичным оператором») имеют самый низкий приоритет среди всех операций Python.

Выражение x if C else y сначала оценивает условие, C ( not x ); если C равно true, x оценивается и возвращается его значение; в противном случае y вычисляется и возвращается его значение.

См. PEP 308 для получения более подробной информации об условных выражениях.

Новое с версии 2.5.

95 голосов
/ 05 мая 2015

Оператор для условного выражения в Python был добавлен в 2006 году как часть Python Enhancement Proposal 308 . Его форма отличается от обычного ?: оператора и это:

<expression1> if <condition> else <expression2>

, что эквивалентно:

if <condition>: <expression1> else: <expression2>

Вот пример:

result = x if a > b else y

Другой синтаксис, который можно использовать (совместимо с версиями до 2.5):

result = (lambda:y, lambda:x)[a > b]()

где операнды лениво оцениваются .

Другим способом является индексирование кортежа (что не согласуется с условным оператором большинства других языков):

result = (y, x)[a > b]

или явно составленный словарь:

result = {True: x, False: y}[a > b]

Другой (менее надежный), но более простой способ - использовать операторы and и or:

result = (a > b) and x or y

однако это не сработает, если x будет False.

Возможное решение - создать списки или кортежи x и y, как показано ниже:

result = ((a > b) and [x] or [y])[0]

или

result = ((a > b) and (x,) or (y,))[0]

Если вы работаете со словарями, вместо использования троичного условного выражения вы можете воспользоваться get(key, default), например:

shell = os.environ.get('SHELL', "/bin/sh")

Источник: ?: в Python в Википедии

86 голосов
/ 06 декабря 2009

К сожалению,

(falseValue, trueValue)[test]

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

Одним из решений этого будет

(lambda: falseValue, lambda: trueValue)[test]()

(выполнение отложено до тех пор, пока победитель не станет известен;)), но оно вносит несоответствие между вызываемыми и не вызываемыми объектами. Кроме того, это не решает проблему при использовании свойств.

Итак, история продолжается: выбор между 3 упомянутыми решениями - это компромисс между наличием функции короткого замыкания, использованием не менее Зython 2.5 (ИМХО больше не проблема) и отсутствием склонности к * trueValue -оценкам -to-false "ошибки.

56 голосов
/ 21 августа 2016

Тернарный оператор на разных языках программирования

Здесь я просто пытаюсь показать важное различие в ternary operator между несколькими языками программирования.

Тернарный оператор в Javascript

var a = true ? 1 : 0;
# 1
var b = false ? 1 : 0;
# 0

Тернарный оператор в Ruby

a = true ? 1 : 0
# 1
b = false ? 1 : 0
# 0

Тернарный оператор в Scala

val a = true ? 1 | 0
# 1
val b = false ? 1 | 0
# 0

Тернарный оператор в R-программировании

a <- if (TRUE) 1 else 0
# 1
b <- if (FALSE) 1 else 0
# 0

Тернарный оператор в Python

a = 1 if True else 0
# 1
b = 1 if False else 0
# 0
55 голосов
/ 25 апреля 2012

Для Python 2.5 и новее существует специальный синтаксис:

[on_true] if [cond] else [on_false]

В старых Pythons троичный оператор не реализован, но его можно смоделировать.

cond and on_true or on_false

Тем не менее, существует потенциальная проблема, которая, если cond оценивается как True, а on_true оценивается как False, то вместо on_true возвращается on_false. Если вы хотите такое поведение, метод в порядке, в противном случае используйте это:

{True: on_true, False: on_false}[cond is True] # is True, not == True

, который можно обернуть в:

def q(cond, on_true, on_false)
    return {True: on_true, False: on_false}[cond is True]

и использовал этот способ:

q(cond, on_true, on_false)

Он совместим со всеми версиями Python.

35 голосов
/ 14 января 2013

Вы часто можете найти

cond and on_true or on_false

но это приводит к проблеме, когда on_true == 0

>>> x = 0
>>> print x == 0 and 0 or 1 
1
>>> x = 1
>>> print x == 0 and 0 or 1 
1

где вы ожидаете для нормального троичного оператора этот результат

>>> x = 0
>>> print 0 if x == 0 else 1 
0
>>> x = 1
>>> print 0 if x == 0 else 1 
1
...