Proposed PEP for a Conditional Expression

thp at thp at
Tue Sep 11 14:26:04 CEST 2001

Michael Chermside <mcherm at> wrote:
:      ARG_1: Workarounds exist.
:          Here are a few workarounds. See also the Python FAQ [1], and
:          the cookbook [2]. First, the things that DON'T work:

:          WORKAROUND_1: (this fails)
:              > def cond(c, a, b):
:              >     if c: return a
:              >    else: return b
:              > x = cond(c, a, b)
:              This fails, because it does not short-circuit... the
:              arguments the the function are always evaluated before
:              the function is invoked. Thus, for instance, the
:              following would not work properly when a == 0:
:              > x = cond( a==0, DEFAULT_VAL, 100/a )

But cond would work if it were a macro.  ;-)

:           WORKAROUND_2: (this SOMETIMES works)
:              > x = c and a or b
:              Because the boolean operators short circuit, this idiom
:              actually works quite nicely some of the time. As long as
:              you are sure that a will evaluate as true, this will do
:              the trick. It's also more readable than the other working
:              solutions, although it is still quite difficult to scan
:              for people not familiar with the idiom. If, however, a
:              evaluates as false, then this fails.

The problem of determining whether or not a given expression ever
evaluates to false is equivalent to determining whether a given Turing
machine halts, i.e., the general case is not algorithmically solvable.
I would like to discourage the use of constructs that introduce
unnecessary occurrences of such concerns.  We need an operator that
works correctly in the general case and should then use it in the
particular case, so that readers can tell what our programs are trying
to do.

:          WORKAROUND_3: (this is the most common idiom)
:              > x = (c and [a] or [b])[0]
:              Here we create one-element lists and index into them.
:              Since [a] is definitely NOT false (it's got 1 element),
:              the and-or syntax will succeed.

This hack make inefficient use of both CPU time and human patience.

:          WORKAROUND_4: (lambda also works)
:              > x = (c and (lambda:a) or (lambda:b))()
:              This is equivalent to WORKAROUND_3, but most people
:              consider it to be slightly less readable, particularly
:              since conditional statements are often used in lambda
:              expressions, thus complicating things further.

This doesn't work if expression a or expression b involves a local

:          WORKAROUND_5: (just write it out!)
:              > if c:
:              >     x = a
:              > else:
:              >     x = b
:              Of course, many people would say that just writing it out
:              is probably the best solution. It can be done in 4 line,
:              or in 2, like this:
:              > if c: x = a
:              > else: x = b
:              In either case, though, this is NOT an expression, so
:              using it may require creating a temporary variable and
:              splitting a formula into two lines, or replacing a lambda
:              expression with a named function.

Compared to a conditional expression this workaround pollutes the
namespace (and the reader's mind) with another name and adds two to
four additional lines of code.

FWIW, here are a couple of additional workaround candidates:

           >  c and a or not c and b
           This hack involves a reevaluation of  c  that can be 
           eliminated from compiled code via common-subexpression 
           elimination.  Also, cascading this hack gets very ugly:
                <cond1> and <exp1> or
                not <cond1> and <cond2> and <exp2> or
                not <cond1> and not <cond2> and <cond3> and <exp3> or

           >  eval( c and "<expression a>" or "<expression b>" )
           I don't like this hack either, but under interpretative 
           execution it's probably more efficient than creating 
           one-member lists (see WORKAROUND_3).

Tom Payne

More information about the Python-list mailing list