If Python does not have a ternary conditional operator, is it possible to simulate one using other language constructs?
转载于:https://stackoverflow.com/questions/394809/does-python-have-a-ternary-conditional-operator
Yes, it was added in version 2.5.
The syntax is:
a if condition else b
First condition
is evaluated, then either a
or b
is returned based on the Boolean value of condition
If condition
evaluates to True a
is returned, else b
is returned.
For example:
>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'
Note that conditionals are an expression, not a statement. This means you can't use assignments or pass
or other statements in a conditional:
>>> pass if False else x = 3
File "<stdin>", line 1
pass if False else x = 3
^
SyntaxError: invalid syntax
In such a case, you have to use a normal if
statement instead of a conditional.
Keep in mind that it's frowned upon by some Pythonistas for several reasons:
If you're having trouble remembering the order, then remember that if you read it out loud, you (almost) say what you mean. For example, x = 4 if b > 8 else 9
is read aloud as x will be 4 if b is greater than 8 otherwise 9
.
Official documentation:
You might often find
cond and on_true or on_false
but this lead to problem when on_true == 0
>>> x = 0
>>> print x == 0 and 0 or 1
1
>>> x = 1
>>> print x == 0 and 0 or 1
1
where you would expect for a normal ternary operator this result
>>> x = 0
>>> print 0 if x == 0 else 1
0
>>> x = 1
>>> print 0 if x == 0 else 1
1
Simulating the python ternary operator.
For example
a, b, x, y = 1, 2, 'a greather than b', 'b greater than a'
result = (lambda:y, lambda:x)[a > b]()
output:
'b greater than a'
An operator for a conditional expression in Python was added in 2006 as part of Python Enhancement Proposal 308. Its form differ from common ?:
operator and it's:
<expression1> if <condition> else <expression2>
which is equivalent to:
if <condition>: <expression1> else: <expression2>
Here is an example:
result = x if a > b else y
Another syntax which can be used (compatible with versions before 2.5):
result = (lambda:y, lambda:x)[a > b]()
where operands are lazily evaluated.
Another way is by indexing a tuple (which isn't consistent with the conditional operator of most other languages):
result = (y, x)[a > b]
or explicitly constructed dictionary:
result = {True: x, False: y}[a > b]
Another (less reliable), but simpler method is to use and
and or
operators:
result = (a > b) and x or y
however this won't work if x
would be False
.
A possible workaround is to make x
and y
lists or tuples as in the following:
result = ((a > b) and [x] or [y])[0]
or:
result = ((a > b) and (x,) or (y,))[0]
If you're working with dictionaries, instead of using a ternary conditional, you can take advantage of get(key, default)
, for example:
shell = os.environ.get('SHELL', "/bin/sh")
Source: ?: in Python at Wikipedia
Absolutely, and it is incredibly easy to understand.
general syntax : first_expression if bool_expression_is_true else second_expression
Example: x= 3 if 3 > 2 else 4
# assigns 3 to x if the boolean expression evaluates to true or 4 if it is false
Does Python have a ternary conditional operator?
Yes. From the grammar file:
test: or_test ['if' or_test 'else' test] | lambdef
The part of interest is:
or_test ['if' or_test 'else' test]
So, a ternary conditional operation is of the form:
expression1 if expression2 else expression3
expression3
will be lazily evaluated (that is, evaluated only if expression2
is false in a boolean context). And because of the recursive definition, you can chain them indefinitely (though it may considered bad style.)
expression1 if expression2 else expression3 if expression4 else expression5 # and so on
Note that every if
must be followed with an else
. People learning list comprehensions and generator expressions may find this to be a difficult lesson to learn - the following will not work, as Python expects a third expression for an else:
[expression1 if expression2 for element in iterable]
# ^-- need an else here
which raises a SyntaxError: invalid syntax
. So the above is either an incomplete piece of logic (perhaps the user expects a no-op in the false condition) or what may be intended is to use expression2 as a filter - notes that the following is legal Python:
[expression1 for element in iterable if expression2]
expression2
works as a filter for the list comprehension, and is not a ternary conditional operator.
You may find it somewhat painful to write the following:
expression1 if expression1 else expression2
expression1
will have to be evaluated twice with the above usage. It can limit redundancy if it is simply a local variable. However, a common and performant Pythonic idiom for this use-case is to use or
's shortcutting behavior:
expression1 or expression2
which is equivalent in semantics. Note that some style-guides may limit this usage on the grounds of clarity - it does pack a lot of meaning into very little syntax.
@up:
Unfortunately, the
(falseValue, trueValue)[test]
solution doesn't have short-circuit behaviour; thus both falseValue and trueValue are evaluated regardless of the condition. This could be suboptimal or even buggy (i.e. both trueValue and falseValue could be methods and have side-effects).
One solution to this would be
(lambda: falseValue, lambda: trueValue)[test]()
(execution delayed until the winner is known ;)), but it introduces inconsistency between callable and non-callable objects. In addition, it doesn't solve the case when using properties.
And so the story goes - choosing between 3 mentioned solutions is a trade-off between having the short-circuit feature, using at least python 2.5 (IMHO not a problem anymore) and not being prone to "trueValue-evaluates-to-false" errors.
For Python 2.5 and newer there is a specific syntax:
[on_true] if [cond] else [on_false]
In older Pythons a ternary operator is not implemented but it's possible to simulate it.
cond and on_true or on_false
Though, there is a potential problem, which if cond
evaluates to True
and on_true
evaluates to False
then on_false
is returned instead of on_true
. If you want this behavior the method is OK, otherwise use this:
{True: on_true, False: on_false}[cond is True] # is True, not == True
which can be wrapped by:
def q(cond, on_true, on_false)
return {True: on_true, False: on_false}[cond is True]
and used this way:
q(cond, on_true, on_false)
It is compatible with all Python versions.
From the documentation:
Conditional expressions (sometimes called a “ternary operator”) have the lowest priority of all Python operations.
The expression
x if C else y
first evaluates the condition, C (not x); if C is true, x is evaluated and its value is returned; otherwise, y is evaluated and its value is returned.See PEP 308 for more details about conditional expressions.
New since version 2.5.
You can index into a tuple:
(falseValue, trueValue)[test]
test
needs to return True or False.
It might be safer to always implement it as:
(falseValue, trueValue)[test == True]
or you can use the built-in bool()
to assure a Boolean value:
(falseValue, trueValue)[bool(<expression>)]
For versions prior to 2.5, there's the trick:
[expression] and [on_true] or [on_false]
It can give wrong results when on_true
has a false boolean value.1
Although it does have the benefit of evaluating expressions left to right, which is clearer in my opinion.
expression1 if condition else expression2
>>> a = 1
>>> b = 2
>>> 1 if a > b else -1
-1
>>> 1 if a > b else -1 if a < b else 0
-1
Here I just try to show some important difference in ternary operator
between a couple of programming languages.
Ternary Operator in Javascript
var a = true ? 1 : 0;
# 1
var b = false ? 1 : 0;
# 0
Ternary Operator in Ruby
a = true ? 1 : 0
# 1
b = false ? 1 : 0
# 0
Ternary operator in Scala
val a = true ? 1 | 0
# 1
val b = false ? 1 | 0
# 0
Ternary operator in R programming
a <- if (TRUE) 1 else 0
# 1
b <- if (FALSE) 1 else 0
# 0
Ternary operator in Python
a = 1 if True else 0
# 1
b = 1 if False else 0
# 0
Now you can see the beauty of python language. its highly readable and maintainable.
you can do this :-
[condition] and [expression_1] or [expression_2] ;
Example:-
print(number%2 and "odd" or "even")
This would print "odd" if the number is odd or "even" if the number is even.
Note :- 0 , None , False , emptylist , emptyString evaluates as False. And any data other than 0 evaluates to True.
if the condition [condition] becomes "True" then , expression_1 will be evaluated but not expression_2 . If we "and" something with 0 (zero) , the result will always to be fasle .So in the below statement ,
0 and exp
The expression exp won't be evaluated at all since "and" with 0 will always evaluate to zero and there is no need to evaluate the expression . This is how the compiler itself works , in all languages.
In
1 or exp
the expression exp won't be evaluated at all since "or" with 1 will always be 1. So it won't bother to evaluate the expression exp since the result will be 1 anyway . (compiler optimization methods).
But in case of
True and exp1 or exp2
The second expression exp2 won't be evaluated since True and exp1
would be True when exp1 isn't false .
Similarly in
False and exp1 or exp2
The expression exp1 won't be evaluated since False is equivalent to writing 0 and doing "and" with 0 would be 0 itself but after exp1 since "or" is used, it will evaluate the expression exp2 after "or" .
Note:- This kind of branching using "or" and "and" can only be used when the expression_1 doesn't have a Truth value of False (or 0 or None or emptylist [ ] or emptystring ' '.) since if expression_1 becomes False , then the expression_2 will be evaluated because of the presence "or" between exp_1 and exp_2.
In case you still want to make it work for all the cases regardless of what exp_1 and exp_2 truth values are, do this :-
[condition] and ([expression_1] or 1) or [expression_2] ;