Как работает обход условного оператора Python? - PullRequest
21 голосов
/ 22 декабря 2009

Из того, что я прочитал, я обнаружил, что встроенного троичного оператора не существует (я буду рад узнать об этом больше.).

Я нашел следующий код в качестве замены:

def val():
    var = float(raw_input("Age:"))
    status = ("Working","Retired")[var>65]
    print "You should be:",status

Я не мог понять, как работает этот код; Может кто-нибудь объяснить мне, как на самом деле работает код? Мне также интересно узнать, почему троичного оператора не существует; любые ссылки или ссылки по этому поводу будут полезны.

Я использую Python 2.6.4 в Windows Vista.

Ответы [ 12 ]

51 голосов
/ 22 декабря 2009

Python имеет конструкцию, похожую на троичный оператор в C, и др. Это работает примерно так:

my_var = "Retired" if age > 65 else "Working"

и эквивалентен этому коду C:

my_var = age > 65 ? "Retired" : "Working";

Что касается того, как работает код, который вы разместили, давайте пройдемся по нему:

("Working","Retired")

создает 2-кортеж (неизменный список) с элементом «Working» в индексе 0 и «Retired» в индексе 1.

var>65

возвращает True, если var больше 65, False, если нет. При применении к индексу он конвертируется в 1 (True) или 0 (False). Таким образом, это логическое значение предоставляет индекс в кортеж, созданный в той же строке.

Почему в Python не всегда был троичный оператор? Простой ответ заключается в том, что Гидо ван Россум, автору Python, не нравился / не хотел этого, очевидно полагая, что это ненужная конструкция, которая может привести к путанице в коде (и любой, кто видел массивные вложенные троичные операторы в С, наверное, согласен). Но для Python 2.5 он смягчился и добавил грамматику, показанную выше.

9 голосов
/ 22 декабря 2009

Python (2.5 и выше) действительно имеет синтаксис для того, что вы ищете:

x = foo if condition else bar

Если condition равно True, x будет установлено на foo, в противном случае оно будет установлено на bar.

Примеры:

>>> age = 68
>>> x = 'Retired' if age > 65 else 'Working'
>>> x
'Retired'
>>> age = 35
>>> y = 'Retired' if age > 65 else 'Working'
>>> y
'Working'
8 голосов
/ 22 декабря 2009

потому что True приводит к 1, а False к 0, так что если var = 70

("Working","Retired")[var>65]

становится

("Working", "Retired")[1]

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

"Retired" if var > 65 else "Working"
7 голосов
/ 22 декабря 2009

индексирование в список

Использование

[expression_when_false, expression_when_true][condition] # or
(expression_when_false, expression_when_true)[condition]

использует тот факт, что в Python True равен (но не является!) 1, а False равен (но не!) 0. Вышеприведенное выражение создает список из двух элементов и использует результат условие для индексации в списке и возврата только одного выражения. Недостатком этого метода является то, что оба выражения оцениваются.

и / или ярлыки

С момента создания Python появилась форма этой операции:

condition and expression_when_true or expression_when_false

Это принимает ярлык и оценивает только одно выражение, но имеет подверженный ошибкам недостаток: expression_when_true не должно вычислять неверное значение, иначе результат будет expression_when_false . and и or являются «короткими замыканиями» в Python, и применяются следующие правила:

a and b #→ a if a is false, else b
a or b  #→ a if a is true, else b

Если условие ложно, то expression_when_true никогда не оценивается, и в результате получается expression_when_false . OTOH, если условие истинно, то результатом является результат ( expression_when_true или expression_when_false ); обратитесь к таблице выше.

троичный условный оператор

Конечно, начиная с Python 2.5, существует троичный условный оператор:

expression_when_true if condition else expression_when_false

Странный (если вы привыкли к C-образному тройному условному оператору) порядок операндов приписывается многим вещам ; общее намерение состоит в том, что условие должно быть истинным большую часть времени, так что наиболее распространенный результат появляется первым и наиболее заметен.

2 голосов
/ 28 декабря 2009

логические выражения короткого замыкания

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

>>> (2+2 == 4) and "Yes" or "No"
'Yes'
>>> (2+2 == 5) and "Yes" or "No"
'No'

В вашем примере:

>>> (int(raw_input("Age: ")) > 65) and "Retired" or "Working"
Age: 20
'Working'
>>> (int(raw_input("Age: ")) > 65) and "Retired" or "Working"
Age: 70
'Retired'

Подробнее об этой технике читайте в Очаровательный Python: функциональное программирование на Python, часть 1 .

0 голосов
/ 22 декабря 2009

пытается дать полный ответ, основываясь на ответах, приведенных здесь.

как вы нашли (пожалуйста, не используйте этот, потому что он не очень читабелен):

def val():
    var = float(raw_input("Age:"))
    status = ("Working","Retired")[var>65]
    print "You should be:",status

с использованием синтаксиса Python 2.5+:

def val():
    var = float(raw_input("Age:"))
    status = "Working" if var>65 else "Retired"
    print "You should be:",status

с использованием другого распространенного метода, все еще предпочитаемого некоторыми людьми:

def val():
    var = float(raw_input("Age:"))
    status = var>65 and "Working" or "Retired"
    print "You should be:",status

Лично я склонен использовать последний, поскольку порядок операндов такой же, как у троичного оператора C.

EDIT: обнаружил некоторые проблемы с последним подходом (спасибо Роберто Бонваллет).
из википедии:

этот код сломался бы, если бы op1 мог быть «ложное» значение (None, False, 0, an пустая последовательность или коллекция,…) как выражение вернет op2 (было ли это правдой или ложью) вместо (ложного) op1

, поэтому мое последнее предложение было бы использовать троичный оператор 2,5+ , поскольку он прост, удобочитаем и обеспечивает поведение при коротком замыкании.

0 голосов
/ 22 декабря 2009

Только строка «status =» этого кода реализует что-то вроде троичного оператора.

status = ("Working","Retired")[var>65]

Это создает двухэлементный кортеж со строками «Working» в индексе 0 и «Retired» в индексе 1. После этого он индексирует в этот кортеж, чтобы выбрать один из двух элементов, используя результаты выражения var > 65.

Это выражение вернет True (эквивалентно 1, поэтому выбрано «Ушел в отставку»), если значение var больше 65. В противном случае оно вернет False (эквивалентно 0, таким образом выбрав «Работающий»).

Между этим подходом и троичным оператором есть ключевое отличие, хотя в вашем конкретном примере это не имеет значения. При подходе индексации кортежа оба значения оцениваются, но возвращается только одно. С троичным оператором, только одно из двух значений фактически оценивается; это называется «коротким замыканием». Это может иметь значение в таких случаях:

status = funcA() if var > 65 else funcB()
status = (funcB(), funcA())[var > 65]

В первом случае, либо funcA () вызывается , либо , вызывается funcB (), но никогда оба. В последнем случае оба они называются первыми, а результаты сохраняются в кортеже - затем выбирается только один, и кортеж отбрасывается.

Это особенно важно понять, если у funcA () или funcB () есть «побочные эффекты», то есть они изменяют другие данные при выполнении.

0 голосов
/ 22 декабря 2009
status = ("Working","Retired")[var>65]

Эта строка работает как троичный оператор, потому что выражение var>65 возвращает 1 или 0, в зависимости от того, больше * 653 * больше 65 или нет. Так что если var>65, то строка становится такой:

status = ("Working","Retired")[1]

то есть второй элемент последовательности ("Working","Retired"). Это выглядит странно, но не так, если вы напишите так:

status_sequence = ("Working","Retired")
status = status_sequence[1]

так status = "Retired".

Точно так же, если var<=65, тогда оно становится

status = ("Working","Retired")[0]

и status = "Working".

0 голосов
/ 22 декабря 2009

Изначально не было троичного оператора, потому что «Явный лучше, чем неявный», и его считали непифоническим. Мне тоже не очень нравится троичная опера python, но она существует:

x = foo if condition else bar

как показано ТМ.

Что касается status = ("Working","Retired")[var>65], var > 65 возвращает логическое значение: True или False; однако, Python довольно слабо обрабатывает логические типы: True - это 1, а False - это 0 в некоторых контекстах. Вы можете проверить это, выполнив >>> True == 1.

0 голосов
/ 22 декабря 2009

это форма с троичным оператором python

def val():
    var = float(raw_input("Age:"))
    status = "Retired" if var > 65 else "Working"
    print "You should be:",status

код, который вы показали, немного хитрый: он создает кортеж из двух элементов, элементы которого находятся в позициях 0 и 1. Для выбора правильного элемента он использует условие, которое возвращает логическое значение, но логические значения в python являются целыми числами, поэтому вы можете использовать это как специальные индексы (они могут быть 0 или 1).

...