Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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 всегда был тройной оператор? Простой ответ заключается в том, что Guido van Rossum, автор Python, не любил/не хотел этого, по-видимому полагая, что это была ненужная конструкция, которая может привести к запутанному коду (и любой, кто видел массово вложенные тернарные операторы в C, вероятно, согласны). Но для Python 2.5 он смягчился и добавил грамматику, показанную выше.

Ответ 2

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'

Ответ 3

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

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

становится

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

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

"Retired" if var > 65 else "Working"

Ответ 4

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

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

[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 никогда не оценивается, а результатом является выражение_when_false. OTOH, если условие истинно, то результатом является результат (выражение_when_true или expression_when_false); см. таблицу выше.

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

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

expression_when_true if condition else expression_when_false

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

Ответ 5

Буферные выражения короткого замыкания

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

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

Ответ 6

В Python 2.6 и выше:

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

В Python 3.1 и выше:

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

Ответ 7

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

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

здесь tuple ("Working","Retired") обращается с индексом [var>65], который вычисляет либо True (1), либо False (0). Когда он получает доступ с индексом 0, status будет 'Working'; если индекс 1, то он будет `` Retired``. Это довольно неясный способ выполнения условного присваивания, используйте обычный тройственный синтаксис, который был введен в py2.5, как было сказано.

Ответ 8

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

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

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

Ответ 9

Первоначально не было троичного оператора, потому что "Явный лучше, чем неявный", и он воспринимался как непитонический. Мне тоже не нравится python trernary op, но он существует:

x = foo if condition else bar

как показано TM.

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

Ответ 10

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

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

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

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

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

so status = "Retired".

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

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

и status = "Working".

Ответ 11

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

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

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

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

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

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

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

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

Ответ 12

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

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

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: нашли некоторые проблемы с последним подходом (спасибо Roberto Bonvallet).
из Википедии:

этот код сломается, если op1 может быть значение "ложь" (None, False, 0, an пустой последовательности или коллекции,...) как выражение будет возвращать op2 (будь то правдивый или фальшивый) вместо фальшивого op1

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