the PHP ternary operator equivalent on Python

Steven D'Aprano steve at REMOVETHIScyber.com.au
Sat Nov 19 02:02:21 EST 2005


On Fri, 18 Nov 2005 21:05:50 -0800, bonono at gmail.com wrote:


> Steven D'Aprano wrote:
>> WHY WHY WHY the obsession with one-liners? What is wrong with the good old
>> fashioned way?
>>
>> if cond:
>>     x = true_value
>> else:
>>     x = false_value
>>
>> It is easy to read, easy to understand, only one of true_value and
>> false_value is evaluated. It isn't a one-liner. Big deal. Anyone would
>> think that newlines cost money or that ever time you used one God killed a
>> kitten.
>>
> How do you put this block into list comprehension or generator
> expression ? Why the obsession of these block style ?

Why do you assume that everything you need for your list comprehension has
to go into a single line? Chances are your list comp already calls
functions, so just create one more for it to use.


py> def describe(cond):
...     if cond:
...         return "odd"
...     else:
...         return "even"
... 
py> L = [describe(n % 2) for n in range(8)]
py> L
['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']

One major advantage is that this makes it easier to test your function
describe() in isolation, always a good thing.

Another advantage is that the idiom "call a function" is extensible to
more complex problems:

def describe(n):
    if n < 0:
        return "negative " + describe(-n)
    elif n == 0:
        return "zero"
    elif n % 2:
        return "odd"
    else:
        return "even"

L = [describe(n) for n in range(8)]

if much easier to understand and follow than using ternary expressions:

# obviously untested
L = ["zero" if n == 0 else \
    "negative " + ("odd" if n % 2 else "even") if n < 0 else \
    "odd" if n % 2 else "even" for n in range(8)]

Yes, I've seen ternary expressions nested three and even four deep.

I find it fascinating to read Guido's reasoning for introducing a ternary
statement. From the PEP here http://www.python.org/peps/pep-0308.html he
links to this comment of his:

[quote]
I think Raymond's example is more properly considered an argument for
adding a conditional expression than for removing the current behavior of
the and/or shortcut operators; had we had a conditional expression, he
wouldn't have tried to use the "x and y or z" syntax that bit him.
[end quote]

Looking back to Raymond's example here: 
http://mail.python.org/pipermail/python-dev/2005-September/056510.html

[quote]
I propose that in Py3.0, the "and" and "or" operators be simplified to
always return a Boolean value instead of returning the last evaluated
argument.

1) The construct can be error-prone.  When an error occurs it can be
invisible to the person who wrote it.  I got bitten in published code
that had survived testing and code review:

  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: type(z)==types.ComplexType and z.real or z)

The code fails silently when z is (0+4i).  It took a good while to trace
down a user reported error (when Matlab results disagreed with my matrix
module results) and determine that the real() method contained an error.
Even when traced down, I found it hard to see the error in the code.
Now that I know what to look for, it has not happened again, but I do
always have to stare hard at any "and/or" group to mentally verify each
case.
[end quote]


Dare I suggest that if Raymond wasn't struggling to force the body of his
function real() to be a one-liner, he wouldn't have tried to use the "x
and y or z" syntax that bit him? Brevity is not always a virtue.


-- 
Steven.




More information about the Python-list mailing list