People coming from C, C++ or Perl might miss the so-called ternary operator ?: (condition ? then-expr : else-expr). It's most often used for avoiding several lines of code and temporary variables for very simple decisions, like printing the plural form of words after a counter (see example code).
There are two ways to get the same effect in Python: selecting one of two values from a tuple, or using the special behaviour of the "and" and "or" operators in Python. The second method has the advantage that only ONE of the two possible expressions is evaluated, and is thus more close to the behaviour of ?: as defined by C.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # explicit if
for i in range(1,3):
if i == 1:
plural = ''
else:
plural = 's'
print "The loop ran %d time%s" % (i, plural)
# selecting from tuple
for i in range(1,3):
print "The loop ran %d time%s" % (i, ('','s')[i != 1])
# short-circuited logical expression
for i in range(1,3):
print "The loop ran %d time%s" % (i, i != 1 and 's' or '')
# Output of all loops:
# The loop ran 1 time
# The loop ran 2 times
|
It may be worth noting that the construct "a and b or c" only works as a simulation of the ternary operator if the value of b is always true (i.e. not any of zero, the empty string, the empty list or None). Hamish Lawson
Important note and another approach. It is very important to point out that
( cond and val_1 or val_2 )
is not the same as( cond ? val_1 : val_2 )
unless val_1 is guaranteed not to be false. <P> Because of this, I would recomend including yet another approach... that of defining a utility function. Here's mine:Then I just use it in code as
And the disadvantage here is that there is no "short-circuiting"... both options are evaluated even if they aren't needed (in the example above, if y==2, then 3*y+1 will still be calculated). <p> -- Michael Chermside Michael Chermside
Accomodating false val_1 while keeping shortcircuit behaviour. As has been noted, the (cond and val_1 or val_2) technique suffers from the fact that val_1 can't be false, while the disadvantage of the function approach is that it doesn't exhibit shortcircuit behaviour. However there is an elaboration of the and-or technique which does accomodate val_1 being false while still exhibiting shortcircuit behaviour (though perhaps it can't claim to be pretty!):
Enclosing val_1 in a list ensures that it will be true. Hamish Lawson
One more variation. Here's a technique that, while it isn't equivalent to a ? b : c, is often applicable in the same situations:
Brent Burley
simulating the ternary operator. The Algorithm category contains an entry by Alex Martelli on exactly this topic, with at least two solutions not included here...
a? b : c emulation is Python FAQ 4.16. There's also an Python FAQ on the topic:
http://www.python.org/cgi-bin/faqw.py?query=ternary&querytype=simple&casefold=yes&req=search
Note that the short circuit behaviour might be really necessary if evaluating b or c has major side effects such as deleting a file. If that's the case I would rather use a plain if-else construct than using (a and [b] or [c])[0] from the FAQ.
If there are no side effects I would prefer (b, c)[not a] or still the if-else thing.
Can also use the overloaded multiplication operator for strings. You can also do
which is as close to obfuscated python as we can get.
iif only you had chosen a better name ;-). Just kidding. I use the exact same utility function and find it much cleaner than any of the approaches in the recipe (maybe it's just me). I chose the name 'iif' because that's what it is called in VB. Whoddathunk I'd ever use VB for inspiration :-)
a bound lambda solution. In the Python FAQ 1.2.11 "Is there an equivalent of C's "?:" ternary operator?" the function solution given is
You need to lambda: b or c if they are functions to prevent execution. However apply() is deprecated since release 2.3.
A much simpler and more efficient solution I use is
you still need to lambda: b or c functions but it does not use deprecated functions.
update. First following stefan's comment I now use
and secondly because this is a short circuit and the arguments are not passed to another function, you dont need to lambda: b or c if it is a fucntion to prevent side effects!
update to update. If only I could edit my comments :-( - You still to lambda b or c if fucntions to avoid side effects.
A more flexible version.
better ternary operator? Hey,
I got the idea for this function from code in "Python and Tkinter Programming" by John E. Grayson:
"ImIf" is for Immediate IF, which is what Microsoft calls it, maybe someone else might call it that, too.
I believe it is truly and demonstrably "lazy". One can test it with these:
def SayTrue(): print "True"
def SayFalse(): print "False"
so
ImIf( Value, SayTrue, SayFalse )()
prints either "True" or "False" but not both.
I hope this is helpful.
Rick Graves
more about ternary operator. This was my first post to the cookbook or similar, and I have learned that I should read the prior postings carefully before adding my own. I had recently finished reading the second edition of the hard copy cookbook, and the ternary operator presented there did not hit the spot for me. I was a little excited after seeing code in "Python and Tkinter Programming" that could be used in a function that would hit the spot.
The file into which I would logically put my function already imported "truth" as a global, so I did not think hard about how to implement the function without it. It is obviously better to use "not", as in Martin Freedman's lambda implementation, as "not" does not need to be imported. So my function could become
So I see two related issues, a) which is better, an anonymous lambda or named function, and b) if using a named function, what should be the name.
Although I am one of those who prefer a function named with def over a lambda any day, for "the ternary operator," I personally would rather call an existing function with a short, descriptive name than type out the lambda line every time I wanted this function.
The name "ternary" has to do with 3, as the function takes 3 parameters/arguments, which seems to be unusual in the C world. But I have lots of functions that take 3 parameters/arguments, so the name "ternary" does not seem descriptive to me. From that standpoint, "immediate if" seems more descriptive, but I admit "immediate if" is already etched into my brain.
But I am not pushing "immediate if" -- if you want to have a named function rather than type out an anonymous lambda, use any name that works for you.
ternary operator and 2.5. I noticed this recipe/thread while browsing for python2.4 ternary-like behavior
It's probably now useful to note that python 2.5 has added a ternary operator of the form:
caseTrue if condition else caseFalse
Also, the name 'ternary' does indeed refer to the 3 arguments taken in the operator. Note, though, that it is descriptive because it is an operator that takes 3 arguments, rather than a function (which can, of course, take an arbitrarily defined number of arguments).
Common operators like '+' and '*' are
binary
because they take two arguments: arg1 + arg2. There is alsounary
, which is the sign on a signed number (+1 or -1). This is where the ternary nomenclature derives from. The previous posters were confusing functions with operators.