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:
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
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.