Как обходное решение условного оператора Python работает?

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

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

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

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

Я запускаю Python 2.6.4 на Windows Vista.

21
задан Mechanical snail 24 September 2012 в 21:39
поделиться

12 ответов

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

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

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

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

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

("Working","Retired")

создает 2-тройку (неизменяемый список) с элементом "Работает" на индексе 0, а "Пенсионер" на индексе 1.

var>65

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

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

.
51
ответ дан 29 November 2019 в 06:18
поделиться

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

x = foo if condition else bar

Если условие истинно, 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'
9
ответ дан 29 November 2019 в 06:18
поделиться

На питоне 2.6 и выше:

print "You should be {0}.".format("retired" if var>65 else "working")

На питоне 3.1 и выше:

print ("You should be {}.".format("retired" if var>65 else "working"))
0
ответ дан 29 November 2019 в 06:18
поделиться

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

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

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

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

and- or shortcuts

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

condition and expression_when_true or expression_when_false

Она принимает комбинацию клавиш и вычисляет только одно выражение, но обладает недостатком, предрасполагающим к ошибкам: expression_when_true не должно вычисляться до неискреннего значения, в противном случае результатом будет expression_when_false. и и или являются "коротким замыканием" на языке питон, и к ним применяются следующие правила:

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

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

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

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

expression_when_true if condition else expression_when_false

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

.
7
ответ дан 29 November 2019 в 06:18
поделиться

Булевые логические операции короткого замыкания

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

>>> (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'

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

.
2
ответ дан 29 November 2019 в 06:18
поделиться

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

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

становится

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

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

"Retired" if var > 65 else "Working"
8
ответ дан 29 November 2019 в 06:18
поделиться

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

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

здесь кортеж ("Рабочий", "Пенсионер") доступен с индексом [var>65], который оценивает либо True (1), либо False (0). Когда он доступен с индексом 0, статус будет "Рабочий" ; если индекс равен 1, то он будет "Пенсионер". Это довольно непонятный способ делать условное присваивание, использовать обычный троичный синтаксис, который, как было сказано, был введен в py2.5.

.
0
ответ дан 29 November 2019 в 06:18
поделиться

Первоначально не было троичного оператора, так как "Explicit is better than implicit", и он считался непитоническим. Мне тоже не слишком нравится троичная операция Питона, но она существует:

x = foo if condition else bar

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

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

.
0
ответ дан 29 November 2019 в 06:18
поделиться
status = ("Working","Retired")[var>65]

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

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

, то есть вторым элементом последовательности ("Работает", "Ушел в отставку"). Это выглядит странно, но не так, если вместо этого написать так:

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

поэтому status = "Retired".

Аналогично, если var<=65, то он становится

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

и status = "Work".

.
0
ответ дан 29 November 2019 в 06:18
поделиться

В этом коде только строка "status =" реализует нечто вроде тернарного оператора.

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

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

Это выражение вернет True (эквивалентно 1, таким образом, пикируя 'Retired'), если значение var больше 65. Иначе оно вернет False (эквивалентно 0, пикируя таким образом 'Work').

Тем не менее, есть ключевое отличие этого подхода от тернарного оператора, хотя в вашем конкретном примере это не имеет значения. При использовании подхода tuple-indexing вычисляются оба значения, но возвращается только одно. При использовании тернарного оператора фактически вычисляется только одно из двух значений, что называется поведением "короткого замыкания". Это может иметь значение в таких случаях как:

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

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

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

.
0
ответ дан 29 November 2019 в 06:18
поделиться

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

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

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

.
0
ответ дан 29 November 2019 в 06:18
поделиться

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

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

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

используя синтаксис питона 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, a пустая последовательность или коллекция, ...) как выражение вернет op2 (неважно, правда это или фальшивка) вместо (фальшивого) op1

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

.
0
ответ дан 29 November 2019 в 06:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: