1. `is` really shouldn't be used for string comparison. It checks object identities rather than string equality, which is broken here for two reasons: first, because it depends on the interpreter to keep one true copy of `''` (which CPython seems to do, but doesn't have to by the spec), and, second, it doesn't even work consistently in CPython anyway if `expr` is a Unicode string, since `'' is not u''`. (Try replacing `expr` with `u'28+32+++32++39'` and you'll get an error.)
2. If an object is known to be a string, test non-emptiness by testing the string itself: `bool('') == False`, whereas `bool('any other string') == True`. It's more concise and is equally clear to someone comfortable with Python.
I agree that the given example of functional programming is pretty ugly (though it might've been chosen just to illustrate the author's specific points), but I think the version below is really quite nice and won't break on the string comparison.
expr = '28+32+++32++39'
print sum(int(i) for i in expr.split('+') if i)
Because with map you can use any function and sum maps __add__. It also illustrates passing functions as arguments.
More subtly, a generator (or list comprehension) implies the order in which the results are generated and an implicit but observable changing state. If I'm trying to write (or, at least, express, since we are talking about Python) parallelism, map would be a better choice.
More subtly, a generator (or list comprehension) implies the order in which the results are generated and an implicit but observable changing state. If I'm trying to write (or, at least, express, since we are talking about Python) parallelism, map would be a better choice.
This is definitely not true -- generator expressions can be expressed using lazy list semantics. By your logic every Haskell list comprehension would be stateful.
I would encourage you to write the denotational or operational semantics of your expressions in these matters rather than simply going by intuition.
> generator expressions can be expressed using lazy list semantics
That does not change the fact the results are given in a certain order. Lazy list semantics means the data will be calculated as it's needed, therefore, the calculation cannot be parallelized.
Once again, that doesn't semantically make a difference, unless the loop is side-effecting. However, even without side effects, Python cannot necessarily make any kind of guarantee about such computations since arrays are mutable and can be modified out from under the map.
This is why parmap equivalents take iterables in Python, not arrays. It doesn't matter if you have lazy or eager semantics, only if your semantics are side-effecting.
It's more general than `sum(generator)` - you could write `reduce(mul, ...)` or anything else, while with sum you'll get sum and nothing more. Also, I have no problem with `reduce(some_fun, (x for x in iterable))`, which works too.
Generally, while `map` in python is much better written as list comprehension or generator expression, reduce has no equivalent short of explicit loop with accumulator variable.
Generator expressions are a nice addition to Python, but can't replace everything. It doesn't hold some properties, like partial application. In the end it's sugar that works well as one-line loops, but I don't find the result elegant when you mix and match with other high-order functions, lambdas, or when nested. It turns into a prefix/postfix/infix mess.