Charles Menguy
Charles Menguy

Reputation: 41428

Best way to do ternary conditionals in Python < 2.5

I have to bear with a Python version < 2.5 (it is 2.4.3 for specifics)

It seems that ternary operators were introduces in Python starting at 2.5. For those who are not familiar, ternary operators in Python >= 2.5 look like this:

def do_ternary(flag):
    return "foo" if flag else "bar"

I'd like to know some solutions to emulate this in the early versions of Python. I can for sure do it with if ... else, but I'm looking for something more pythonic that I wouldn't be ashamed to put on some production-level code :)

Thanks for the help !

Upvotes: 2

Views: 1230

Answers (4)

Charles Menguy
Charles Menguy

Reputation: 41428

Actually I was looking on the web and found what seems like a really elegant pythonic solution:

def _if(test):
    return lambda alternative: \
               lambda result: \
                   [delay(result), delay(alternative)][not not test]()

def delay(f):
    if callable(f): return f
    else: return lambda: f

>>> fact = lambda n: _if (n <= 1) (1) (lambda: n * fact(n-1))
>>> fact(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000L

What do you think about this one? It looks pretty clean and easy to read in my opinion.

Upvotes: 5

Aaron Dufour
Aaron Dufour

Reputation: 17505

A common trick is to use list-indexing, since False/True turn into 0/1 when an integer is required. In case the test may be false-y or truth-y rather than a boolean, its good practice to first ensure the test is a boolean:

["bar", "foo"][bool(flag)]

will produce the same output as the ternary in your question.

Edit: Dougal points out that this may behave slightly differently from the ternary, because both the true and false values will be evaluated, which may have side-effects.

Upvotes: 4

SingleNegationElimination
SingleNegationElimination

Reputation: 156158

the correct way that does all of the things that if/else does is:

(condition and (yes_value,) or (no_value,))[0]

which does both the short circuiting and resolves the problem of when yes_value is itself falsey. Obviously, if you have reason to avoid this cludge, just do that; in your example, both conditions are constant expressions, so you can do:

{True: yes_value, False: no_value}[bool(condition)]

or more tersely:

(no_value, yes_value)[condition]

if you do need the short circut, but you're confident that the yes_value is never falsey, you can trim out the tuple:

 condition and yes_value or no_value

but that's probably only valid when the yes_value is actually a constant. If none of these suit your tastes or needs, just use a plain-ol if: statement, with an intermediate variable

if condition:
    result = yes_value
else:
    result = no_value

Upvotes: 8

Gareth Latty
Gareth Latty

Reputation: 89007

The classic 'trick' used to do this is:

test and true_value or false_value

This works as and and or work like so in python:

x or y   ->    if x is false, then y, else x
x and y  ->    if x is false, then x, else y

Source

This means that we get the roughly the same result - so long as true_value evaluates to True - so, for example, the following would not work:

flag and [] or "bar"

As [] evaluates to False.

I'd still argue that this is less readable than simply using an if/else block, as unless you are familiar with it, it's unclear.

So I'd advise using:

if test:
    return true_value
else:
    return false_value

(replacing return with assignment or whatever where needed).

Upvotes: 1

Related Questions