[Python-Dev] Adding a conditional expression in Py3.0

Nick Coghlan ncoghlan at gmail.com
Wed Sep 21 00:30:13 CEST 2005

Steven Bethard wrote:
> Guido van Rossum wrote:
>>I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no
>>colons. None of the other  expression forms (list comprehensions and
>>generator expressions) involving statement keywords use colons.
> FWIW, I find this quite intuitive.  It follows the same pattern as LCs
> and GEs -- remove the colons and add parentheses (or brackets for
> LCs).  So I'm +1.

*But*, in LC's and GE's, the body of the main clause of the statement is also 
pulled out and placed in front of the keyword:

   def gen():
     for VAR in ITERABLE:
       if COND:
         yield EXPR


   gen = (EXPR for VAR in ITERABLE if COND)

This makes sense to me, because the most important thing in the generator 
expression is the way each element is populated - the source iterable and the 
filtering condition do matter, but they aren't as important.

It also makes the expression forms more declarative in nature, rather than 
being procedural statements embedded inside an expression.

Notice also that, in this case, if ITERABLE is empty, or COND always evaluates 
false in boolean context, then EXPR is never executed - in other words, Python 
already has precedent for out of order code execution in expression evaluation.

Guido's original PEP 308 proposal worked much the same way:

   if COND:
      x = EXPR1
      x = EXPR2


   x = (EXPR1 if COND else EXPR2)

I see this as similar in spirit to the current form of LC's and GE's - the 
most important things are the two possible values rather than the condition 
for choosing between them, and this form makes them clearly visible at the 
start and end of the expression, rather than embedding one of them in the 
middle. The post-filtered form is also similarly declarative rather than 

This version doesn't need a separate 'elif' form - elif can be written as:

   x = (EXPR1 if COND1 else EXPR2 if COND2 else EXPR3)

Note that the keyword count is no higher than if 'elif' was used, because the 
'then' keyword isn't needed:
   x = (if COND1 then EXPR1 elif COND2 then EXPR2 else EXPR3)

Here's Raymond's problematic example using this original PEP 308 form:
   def real(self):
     'Return a vector with the real part of each input element'
     # do not convert integer inputs to floats
     return self.map(lambda z:
                       (z.real if type(z)==types.ComplexType else z))

And the other non-colon, keyword based proposal in PEP 308's top four:

   def real(self):
     'Return a vector with the real part of each input element'
     # do not convert integer inputs to floats
     return self.map(lambda z:
                       (if type(z)==types.ComplexType then z.real else z))

Another common use case would be for mutable default arguments:

   x = ([] if arg is None else list(arg))
   x = (if arg is None then [] else list(arg))

Basically, I'm +1 on the original PEP 308 form because it reads more naturally 
(and more like LC's and GE's) to me in expression contexts, and +0 on the 
"if/then/elif/else" form (because I would like a real conditional operator).


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-Dev mailing list