The Python syntax for conditional expressions (introduced in Python 2.5) is
trueval if cond else falseval
I think this is bloody awful. Why couldn’t they have adopted the standard C syntax, as used in a whole bunch of other C-derivative languages?
cond ? trueval : falseval
On the bright side, there are some alternative constructs that allow you to avoid that horrible syntax. Here’s one I have used a few times:
(falseval, trueval)[cond]
For example:
NrRows = (3, 5)[LargeTable]
The main disadvantage with this is that it doesn’t do short-circuit evaluation: both falseval and trueval are always evaluated, regardless of the value of cond. For example, this will crash with a “TypeError: ‘NoneType’ object is not subscriptable” if Dict happens to be None:
Value = (None, Dict[Key])[Dict != None]
It also requires that cond evaluate to 0, 1, True or False, not allowing other types of values like standard Python conditionals, but I don’t see this as a disadvantage.
Here is another form I have seen suggested:
cond and trueval or falseval
For example (rewriting the crashing example above):
Value = Dict != None and Dict[Key] or None
This one correctly short-circuits the evaluation of the arms of the conditional, provided that trueval does not return a value that can be interpreted as false. In other words, it can malfunction in mysterious ways if you’re not careful.
Finally, here’s an idea I came up with, which introduces short-circuit evaluation into the first alternative I mentioned above:
(lambda : falseval, lambda : trueval)[cond]()
For example:
Value = (lambda : None, lambda : Dict[Key])[Dict != None]()
Don’t you just love lambda-expressions?
But Wait, There’s More
This idea can be carried further. Some languages have case-expressions, which are the expression equivalent of switch/case statements. The above lambda-using template can be extended to implement these, either as simple indexing into an array of alternatives:
(
lambda : case_0_expr,
lambda : case_1_expr,
lambda : case_2_expr,
…
)[index]()
which evaluates to case_0_expr if index equals 0, case_1_expr if index equals 1 and so on; or by a more general table lookup:
{
key1 : lambda : case_key1_expr,
key2 : lambda : case_key2_expr
key3 : lambda : case_key3_expr,
…
}[selector]()
which evaluates to case_key1_expr if selector equals key1, case_key2_expr if selector equals key2 and so on. This last form can also be extended to include a default case, if selector matches none of the keyed alternatives:
{
key1 : lambda : case_key1_expr,
key2 : lambda : case_key2_expr
key3 : lambda : case_key3_expr,
…
}.get(selector, lambda : default_expr)()