Если в Python нет тернарного условного оператора, возможно ли имитировать его, используя другие языковые конструкции?
case [...] { when ... then ...} [ else ... ] endаналогичный эффект, но никак не троичный.
Если в Python нет тернарного условного оператора, возможно ли имитировать его, используя другие языковые конструкции?
case [...] { when ... then ...} [ else ... ] endаналогичный эффект, но никак не троичный.
Ответы:
Да, это было добавлено в версии 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 " «Удивительно» поведение использовать его (они могут изменить порядок аргументов).if» может быть очень полезным и сделать ваш скрипт более кратким, он действительно усложнит ваш код)Если у вас возникают проблемы с запоминанием порядка, помните, что когда вы читаете вслух, вы (почти) говорите, что имеете в виду. Например, x = 4 if b > 8 else 9читается вслух как x will be 4 if b is greater than 8 otherwise 9.
Официальная документация:
f(x) = |x| = x if x > 0 else -xдля математиков это звучит очень естественно. Вы также можете понять это, как и A в большинстве случаев, за исключением случаев, когда C, тогда вы должны вместо этого делать B ...
z = 3 + x if x < y else y. Если x=2и y=1, вы можете ожидать, что это даст 4, но это на самом деле приведет к 1. z = 3 + (x if x > y else y)это правильное использование.
z = 3 + x if x < y else 3 + y), либо сгруппировать условное выражение ( z = 3 + (x if x < y else y)или z = (x if x < y else y) + 3)
Вы можете индексировать в кортеж:
(falseValue, trueValue)[test]
testдолжен вернуть True или False .
Может быть безопаснее всегда реализовывать это как:
(falseValue, trueValue)[test == True]
или вы можете использовать встроенное, bool()чтобы обеспечить логическое значение:
(falseValue, trueValue)[bool(<expression>)]
(lambda: print("a"), lambda: print("b"))[test==true]()
[]s, может быть произвольным выражением. Кроме того, для безопасности вы можете явно проверить на правдивость, написав [bool(<expression>)]. Эта bool()функция существует с v2.2.1.
Trueи Falseв качестве ключей: {True:trueValue, False:falseValue}[test] я не знаю, является ли это менее эффективным, но он, по крайней мере, избегает всего «элегантный» против «некрасивых» дебатов. Там нет двусмысленности, что вы имеете дело с логическим, а не с Int.
Для версий до 2.5 есть хитрость:
[expression] and [on_true] or [on_false]
Он может давать неправильные результаты, когда on_true
имеет ложное логическое значение. 1
Хотя он имеет преимущество оценки выражений слева направо, что, на мой взгляд, более понятно.
<expression 1> if <condition> else <expression 2>
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
Из документации :
Условные выражения (иногда называемые «троичным оператором») имеют самый низкий приоритет среди всех операций Python.
Выражение
x if C else yсначала оценивает условие, C ( не x ); если C истинно, x вычисляется и возвращается его значение; в противном случае вычисляется y и возвращается его значение.См. PEP 308 для более подробной информации об условных выражениях.
Новое с версии 2.5.
Оператор для условного выражения в Python был добавлен в 2006 году как часть предложения 308 по улучшению Python . Его форма отличается от обычного ?:оператора, и это:
<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 в Википедии
result = {1: x, 0: y}[a > b]другой возможный вариант ( Trueи Falseна самом деле целые числа со значениями 1и 0)
К сожалению,
(falseValue, trueValue)[test]
решение не имеет поведения короткого замыкания; при этом оба falseValueи trueValueоцениваются независимо от состояния. Это может быть неоптимальным или даже багги (т.е. как trueValueи falseValueмогут быть методы и имеют побочные эффекты).
Одним из решений этого было бы
(lambda: falseValue, lambda: trueValue)[test]()
(выполнение откладывается до тех пор, пока победитель не станет известен;)), но оно вносит несоответствие между вызываемыми и не вызываемыми объектами. Кроме того, это не решает проблему при использовании свойств.
Итак, история продолжается: выбор между 3 упомянутыми решениями является компромиссом между наличием функции короткого замыкания, использованием как минимум Зython 2.5 (ИМХО больше не проблема) и отсутствием склонности к ошибкам « trueValue-оценивается-ложно» ,
if else if.
Здесь я просто пытаюсь показать некоторые важные различия ternary operatorмежду парой языков программирования.
Тернарный оператор в Javascript
var a = true ? 1 : 0;
# 1
var b = false ? 1 : 0;
# 0
Троичный оператор в рубине
a = true ? 1 : 0
# 1
b = false ? 1 : 0
# 0
Тернарный оператор в Скале
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
Для Python 2.5 и новее существует специальный синтаксис:
[on_true] if [cond] else [on_false]
В старых Pythons троичный оператор не реализован, но его можно смоделировать.
cond and on_true or on_false
Тем не менее, существует потенциальная проблема, которая, если condоценивает Trueи on_trueоценивает, Falseзатем on_falseвозвращается вместо on_true. Если вы хотите это поведение, метод в порядке, в противном случае используйте это:
{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.
q("blob", on_true, on_false)возвращает on_false, тогда как on_true if cond else on_falseвозвращает on_true. Обойти это можно заменить condс cond is not Noneв этих случаях, несмотря на то, что не является идеальным решением.
bool(cond)вместо cond is True? Первый проверяет достоверность cond, последний проверяет равенство указателей с Trueобъектом. Как подчеркнул @AndrewCecil, "blob"это правда, но это is not True.
[on_false, on_True][cond is True]чтобы выражение стало короче.
Вы можете часто находить
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
Есть ли в Python троичный условный оператор?
Да. Из файла грамматики :
test: or_test ['if' or_test 'else' test] | lambdef
Интересная часть:
or_test ['if' or_test 'else' test]
Итак, троичная условная операция имеет вид:
expression1 if expression2 else expression3
expression3будет лениво оцениваться (то есть оцениваться только если expression2ложно в логическом контексте). И из-за рекурсивного определения вы можете связывать их бесконечно (хотя это может считаться плохим стилем).
expression1 if expression2 else expression3 if expression4 else expression5 # and so on
Обратите внимание, что каждый ifдолжен сопровождаться else. Люди, изучающие списки и выражения-генераторы, могут найти этот урок трудным для изучения - следующее не сработает, так как Python ожидает третьего выражения для else:
[expression1 if expression2 for element in iterable]
# ^-- need an else here
который поднимает SyntaxError: invalid syntax. Таким образом, вышеприведенное является либо неполной частью логики (возможно, пользователь ожидает запрета в ложном состоянии), либо может быть предназначено для использования expression2 в качестве фильтра - отмечает, что следующее является допустимым Python:
[expression1 for element in iterable if expression2]
expression2работает как фильтр для понимания списка и не является троичным условным оператором.
Вам может быть немного больно писать следующее:
expression1 if expression1 else expression2
expression1нужно будет оценить дважды с использованием вышеуказанного. Это может ограничить избыточность, если это просто локальная переменная. Тем не менее, распространенная и эффективная идиома Pythonic для этого варианта использования заключается в использовании orсокращенного поведения:
expression1 or expression2
что эквивалентно в семантике. Обратите внимание, что некоторые руководства по стилю могут ограничивать это использование из соображений ясности - оно содержит много смысла в очень небольшом синтаксисе.
expression1 or expression2быть похожим и иметь те же недостатки / позитивы, что и expression1 || expression2в javascript
expressionNдля всех экземпляров непротиворечиво, это может быть проще для понимания с помощью именования, которое отличает выражение условного теста от двух выражений результата; например, result1 if condition else result2. Это особенно очевидно при вложении (или цепочке) result1 if condition1 else result2 if condition2 else result3. Видите, насколько лучше это звучит так?
Имитация троичного оператора питона.
Например
a, b, x, y = 1, 2, 'a greather than b', 'b greater than a'
result = (lambda:y, lambda:x)[a > b]()
вывод:
'b greater than a'
result = (y, x)[a < b]Почему вы используете lambdaфункцию ?
Тернарный условный оператор просто позволяет тестировать условие в одной строке, заменяя многострочное if-else, делая код компактным.
[on_true] if [expression] else [on_false]
# Program to demonstrate conditional operator
a, b = 10, 20
# Copy value of a in min if a < b else copy b
min = a if a < b else b
print(min) # Output: 10
# Python program to demonstrate ternary operator
a, b = 10, 20
# Use tuple for selecting an item
print( (b, a) [a < b] )
# Use Dictionary for selecting an item
print({True: a, False: b} [a < b])
# lamda is more efficient than above two methods
# because in lambda we are assure that
# only one expression will be evaluated unlike in
# tuple and Dictionary
print((lambda: b, lambda: a)[a < b]()) # in output you should see three 10
# Python program to demonstrate nested ternary operator
a, b = 10, 20
print ("Both a and b are equal" if a == b else "a is greater than b"
if a > b else "b is greater than a")
Вышеуказанный подход можно записать так:
# Python program to demonstrate nested ternary operator
a, b = 10, 20
if a != b:
if a > b:
print("a is greater than b")
else:
print("b is greater than a")
else:
print("Both a and b are equal")
# Output: b is greater than a
if-elseв действительности не является перезаписью тернарного оператора, и будет выдавать разные выходные данные для значений выбора a и b (в частности, если один является типом, который реализует странный __ne__метод).
ты можешь сделать это :-
[condition] and [expression_1] or [expression_2] ;Пример:-
print(number%2 and "odd" or "even")Это выведет «нечетное», если число нечетное, или «четное», если число четное.
Примечание: - 0, None, False, emptylist, emptyString оценивается как False. И любые данные, кроме 0, оцениваются как True.
если условие [условие] становится «Истиной», тогда выражение_1 будет оцениваться, но не выражение_2. Если мы "и" что-то с 0 (ноль), результат всегда будет быстрым. Так в приведенном ниже утверждении,
0 and exp
Выражение exp не будет оцениваться вообще, так как «и» с 0 всегда будет равняться нулю, и нет необходимости оценивать выражение. Так работает сам компилятор на всех языках.
В
1 or exp
выражение exp вообще не будет оцениваться, так как «или» с 1 всегда будет равно 1. Таким образом, оно не будет мешать вычислению выражения exp, так как результат все равно будет равен 1. (методы оптимизации компилятора).
Но в случае
True and exp1 or exp2
Второе выражение exp2 не будет оцениваться, поскольку True and exp1будет True, если exp1 не false.
Точно так же в
False and exp1 or exp2
Выражение exp1 не будет оцениваться, поскольку False эквивалентно записи 0 и выполнению «и» с 0 будет само 0, но после exp1, так как «или» используется, оно будет вычислять выражение exp2 после «или».
Примечание: - Этот вид ветвления с использованием «или» и «и» можно использовать только тогда, когда выражение_1 не имеет значения Истина False (или 0, или Нет, или emptylist [], или emptystring ''.), Поскольку, если выражение_1 становится False, тогда выражение_2 будет оцениваться из-за наличия «или» между exp_1 и exp_2.
Если вы все еще хотите, чтобы он работал во всех случаях, независимо от того, какие значения истинности exp_1 и exp_2, сделайте следующее: -
[condition] and ([expression_1] or 1) or [expression_2] ;x = [condition] and ([expression_1] or 1) or [expression_2]и имеет expression_1значение ЛОЖЬ, xбудет 1, не expression_1. Используйте принятый ответ.
Больше подсказка, чем ответ (не нужно повторять очевидное в течение сотых раз), но я иногда использую его как ярлык для однотипных конструкций в таких конструкциях:
if conditionX:
print('yes')
else:
print('nah')
, становится:
print('yes') if conditionX else print('nah')
Некоторые (многие :) могут посчитать это неуместным (даже рубиновым :), но я лично нахожу это более естественным - то есть, как бы вы это выразили нормально, плюс немного более визуально привлекательным в больших блоках кода.
print( 'yes' if conditionX else 'nah' )ваш ответ. :-)
print()в обоих случаях - и это выглядит немного более питоническим, я должен признать :) Но что, если выражения / функции не совпадают - как print('yes') if conditionX else True- чтобы получить print()единственное правдивоеconditionX
print('yes') if conditionX else print('nah')это то, что он дает ошибку SyntaxError в Python2.
print "yes", а в Python 3 - это функция - print("yes"). Это можно решить, используя это как утверждение, или лучше - from future import print_function.
Одна из альтернатив условному выражению Python
"yes" if boolean else "no"
это следующее:
{True:"yes", False:"no"}[boolean]
который имеет следующее хорошее расширение:
{True:"yes", False:"no", None:"maybe"}[boolean_or_none]
Самая короткая альтернатива остается:
("no", "yes")[boolean]
но нет альтернативы
yes() if boolean else no()
если вы хотите избежать оценки yes() и no() , потому что в
(no(), yes())[boolean] # bad
оба no()и yes()оцениваются.
Многие языки программирования, производные от которых Cобычно имеют следующий синтаксис троичного условного оператора:
<condition> ? <expression1> : <expression2>
Во - первых,
PythonB enevolent D ictator F или L Ифе (я имею в виду Гвидо ван Россум, конечно) отверг его (как не вещий стиль), так как это довольно трудно понять , для людей , не привыкли кCязыку. Кроме того, знак двоеточия:уже имеет много примененийPython. После того, как PEP 308 был утвержден,Pythonнаконец-то получил собственное условное выражение (что мы используем сейчас):
<expression1> if <condition> else <expression2>
Итак, во-первых, он оценивает состояние. Если он вернется True, выражение1 будет оценено для получения результата, в противном случае выражение2 будет оценено. Из-за механики Lazy Evaluation - будет выполнено только одно выражение.
Вот несколько примеров (условия будут оцениваться слева направо):
pressure = 10
print('High' if pressure < 20 else 'Critical')
# Result is 'High'
Тернарные операторы могут быть соединены последовательно:
pressure = 5
print('Normal' if pressure < 10 else 'High' if pressure < 20 else 'Critical')
# Result is 'Normal'
Следующий такой же, как предыдущий:
pressure = 5
if pressure < 20:
if pressure < 10:
print('Normal')
else:
print('High')
else:
print('Critical')
# Result is 'Normal'
Надеюсь это поможет.
Как уже ответили, да, в python есть троичный оператор:
<expression 1> if <condition> else <expression 2>
Дополнительная информация:
Если <expression 1>это условие, вы можете использовать оценку короткого замыкания :
a = True
b = False
# Instead of this:
x = a if a else b
# You could use Short-cirquit evaluation:
x = a or b
PS: Конечно, оценка короткого замыкания не является троичным оператором, но часто троичный используется в случаях, когда короткого замыкания будет достаточно.
short-circuitоценки.
ДА, у python есть троичный оператор, вот синтаксис и пример кода, чтобы продемонстрировать то же самое :)
#[On true] if [expression] else[On false]
# if the expression evaluates to true then it will pass On true otherwise On false
a= input("Enter the First Number ")
b= input("Enter the Second Number ")
print("A is Bigger") if a>b else print("B is Bigger")
printдействительно не очень хороший выбор, так как это даст SyntaxError в Python2.
Python имеет троичную форму для заданий; однако может быть даже более короткая форма, о которой люди должны знать.
Очень часто нужно присваивать переменной то или иное значение в зависимости от условия.
>>> li1 = None
>>> li2 = [1, 2, 3]
>>>
>>> if li1:
... a = li1
... else:
... a = li2
...
>>> a
[1, 2, 3]
^ Это длинная форма для выполнения таких заданий.
Ниже представлена троичная форма. Но это не самый лаконичный способ - см. Последний пример.
>>> a = li1 if li1 else li2
>>>
>>> a
[1, 2, 3]
>>>
С Python вы можете просто использовать orдля альтернативных назначений.
>>> a = li1 or li2
>>>
>>> a
[1, 2, 3]
>>>
Вышеприведенное работает, поскольку li1is Noneи interp интерпретирует это как False в логических выражениях. Затем interp перемещается и оценивает второе выражение, которое Noneне является пустым списком, и поэтому оно присваивается a.
Это также работает с пустыми списками. Например, если вы хотите назначить aсписок, в котором есть элементы.
>>> li1 = []
>>> li2 = [1, 2, 3]
>>>
>>> a = li1 or li2
>>>
>>> a
[1, 2, 3]
>>>
Зная это, вы можете просто выполнять такие задания, когда сталкиваетесь с ними. Это также работает со строками и другими итерациями. Вы можете назначить aлюбую строку, которая не является пустой.
>>> s1 = ''
>>> s2 = 'hello world'
>>>
>>> a = s1 or s2
>>>
>>> a
'hello world'
>>>
Мне всегда нравился троичный синтаксис Си, но Python делает еще один шаг вперед!
Я понимаю, что некоторые могут сказать, что это не очень хороший стилистический выбор, потому что он основан на механике, которая не сразу очевидна для всех разработчиков. Я лично не согласен с этой точкой зрения. Python - это язык с богатым синтаксисом и множеством идиоматических трюков, которые не сразу бросаются в глаза даблеру. Но чем больше вы изучаете и понимаете механику базовой системы, тем больше вы цените ее.
Другие ответы правильно говорят о троичном операторе Python. Я хотел бы дополнить упоминанием сценария, для которого часто используется троичный оператор, но для которого есть лучшая идиома. Это сценарий использования значения по умолчанию.
Предположим, мы хотим использовать option_valueзначение по умолчанию, если оно не установлено:
run_algorithm(option_value if option_value is not None else 10)
или просто
run_algorithm(option_value if option_value else 10)
Тем не менее, лучшее решение - просто написать
run_algorithm(option_value or 10)
если переменная определена, и вы хотите проверить, имеет ли она значение, вы можете просто a or b
def test(myvar=None):
# shorter than: print myvar if myvar else "no Input"
print myvar or "no Input"
test()
test([])
test(False)
test('hello')
test(['Hello'])
test(True)
будет выводить
no Input
no Input
no Input
hello
['Hello']
True
x if x else y, но нет x if z else y.
Аккуратный способ связать несколько операторов:
f = lambda x,y: 'greater' if x > y else 'less' if y > x else 'equal'
array = [(0,0),(0,1),(1,0),(1,1)]
for a in array:
x, y = a[0], a[1]
print(f(x,y))
# Output is:
# equal,
# less,
# greater,
# equal
Я считаю громоздким синтаксис Python по умолчанию val = a if cond else b, поэтому иногда я делаю это:
iif = lambda (cond, a, b): a if cond else b
# so I can then use it like:
val = iif(cond, a, b)
Конечно, у него есть недостаток - всегда оценивать обе стороны (a и b), но синтаксис мне понятнее
val = a if cond else bутверждение.