This article was written in 2001, and python now includes first-class constructs for many of these.
Map:
>>> [ord(char) for char in "Hello"]
[72, 101, 108, 108, 111]
Filter:
>>> [x for x in xrange(10) if x % 2]
[1, 3, 5, 7, 9]
For laziness, use parenthesis to turn the above list comprehensions into a generator comprehension. Though I don't demonstrate it, you can work over infinite sequences of objects this way with constant memory usage (without allocating all of them upfront).
>>> gen = (x for x in range(10) if x % 2)
>>> gen
<generator object <genexpr> at 0xb729f6bc>
>>> for element in gen:
... print element
...
1
3
5
7
9
The functions are more first-class than list comprehensions and other syntactic alternatives. It's easier, both conceptually and lexically, to mangle, pass around, chain, and combine functions and function argument than it is to write nested list comprehensions.
Not against list comprehensions per se, really. They're just a convenient subset for most commonly idiomatic sequence-mangling-spells, but that's most of what they're good for.
They are using the old 'foo and bar or baz' style as a cheap substitute for the ternary operator. That should be 'bar if foo else baz' in modern Python.
Although I'm fond of using some functional constructs where they make sense, I don't like functional languages and this article is an example of why: in search for a functional style, clear code becomes opaque and simple code becomes complex.
I've both written and read code in non-functional languages where the "easy" way of doing it is thrown aside for the "cool functional" way of doing it. Leading to code which was more fun to write, looks cooler, but is also hard to read and written in a different idiom to the actual programming language. Bad.
I'm 100% guilty of this, although I try to stay vigilant. The other day I refactored out a gnarly bit of a Python API, but caught myself feeling sad because it meant deleting a bunch of clever lambda functions I was using to work around it in the first place. Bad!
That said, the other side of the double-edged sword is great - things that lead to giant tangled messes of procedural code can be turned into very nice functional-style constructs. Also, I love having list comprehensions in Python.
Usually list comprehensions are a much cleaner way to write a map. This I love.
Personally what I love most about using more functional code aren't the clever lambda's and stuff, I actually try to avoid that because it looks weird in Python. What's really awesome is enclosing named functions inside bigger functions and using closures.
The result is code where:
1. nobody can, by accident or intentionally, use inner functions of your algorithm,
2. self-documented code (function name says what the code block does)
3. you aren't passing a gazillion parameters around
4. or making everything messy with a bunch of unneeded OOP code. [I don't like useless OOP code. Objects-just-for-the-sake-of-encapsulation are silly.]
> Usually list comprehensions are a much cleaner way to write a map.
But the first makes my intent clearer than the second:
map(f, xs)
[f(x) for x in xs]
In Python, where creating anonymous functions is syntactically expensive, list-comprehension syntax may be cheaper in many cases, but it's not clearer. When I want to map or filter something, I want to _say_ that I'm mapping or filtering, not explain to Python how to map or filter that thing in terms of list-comprehension syntax. Nor do I want to burden the reader with interpreting that syntax to figure out that it's a mapping or filtering operation.
I want my code to say what I mean, not just evaluate to what I mean.
>But the first makes my intent clearer than the second
That is entirely a matter of opinion. I would say python programmers with no functional background would find the list comprehension clearer, because that is the idiomatic python way.
May would have no idea what map even does without looking it up on the net.
It isn't entirely a matter of opinion, is it? When you use map to do your mapping, aren't you are stating your intent in the language of the profession? The name of the function, after all, is "map," and isn't this term's meaning rather firmly established in mathematics and computer science? So, the idea of calling a map a map has some precedent that we can use to justify the practice, doesn't it?
Now, if your audience has no notion of what a mapping is, then, yes, there's a level of semantic intent that you're not going to be able to communicate to them. (At least until they learn the concept; it's common, worth learning, and not hard to grasp.) But that doesn't mean that you should refuse to call an important concept by its established name.
Concepts, after all, earn their names for a reason. If a concept has one, it's probably best to use it.
> I want my code to say what I mean, not just evaluate to what I mean.
This is an awesome rule of thumb. A more succinct version of Knuth's "Programs are meant to be read by humans and only incidentally for computers to execute"
> the first makes my intent clearer than the second:
I really think the beauty of list comprehensions may be in the eye of the beholder.
I personally find the list comprehension syntax easier to read than equivalent map syntax most of the time, especially (as you point out) for cases where you want an anonymous function (ie quite often), but even for simple ones like your example.
Doubly so when you start chaining map & filter functionality to do one thing. Statements like [ f(x) for x in xs if g(x) > 3 ] seem to read quite nicely for me. You only need to change two words and you have a pseudocode description: "f(x) for all x in xs where g(x) > 3".
This is obviously subjective, though, and maybe I'm in the minority. I knew list comprehensions before I knew Python, so I'll accept that makes me suspect.
But the first of your examples is cleaner not because of any inherent advantage of list-comprehension syntax but because in Python the syntactic cost of turning an expression into an anonymous function is so high. In other words, you're comparing (cognitive cost of comprehension + low cost of expression) against (cognitive cost of map + high cost of promoting an expression to an anonymous function).
Don't blame map for Python's tax on expression-promotion. ;-)
Its funny you mention that. Ive had the same experience with all my code. I found my C++, Java and Python all become more functional thanks to playing around with haskell!
Priorities and style. First-class functions are available, and a lot of veteran Python programmers, Guido included, don't like an overwhelmingly functional style.
It's considered opaque.
Personally, I like to fiddle with Clojure in my free time.
Map:
Filter: For laziness, use parenthesis to turn the above list comprehensions into a generator comprehension. Though I don't demonstrate it, you can work over infinite sequences of objects this way with constant memory usage (without allocating all of them upfront). Alice, the rabbit hole begins here --> http://docs.python.org/library/itertools.html