Hacker News new | past | comments | ask | show | jobs | submit login
Charming Python: Functional programming in Python (ibm.com)
61 points by m3mb3r on Dec 21, 2010 | hide | past | favorite | 24 comments



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

Alice, the rabbit hole begins here --> http://docs.python.org/library/itertools.html


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.


It’s an article from 2001....


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 think more people would read more ibm dev articles if they changed the css a little bit


Readability does a really really good job of cleaning it up.

Is there a way to link to a readability version of a document? Like http://readability.org/?url=example.com


Note:

> Date: 01 Mar 2001

Some of this advice is deprecated.


Is there an updated version of this? Would be really good to see the full list of improvements in this space.


Ever since I've dabbled a bit with Lisp my Python (and javascript) code has become much more functional-y.

Still not sure whether this is a good or bad thing.


I think it's a double-edged sword.

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

edited for wall-of-text


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


> That is entirely a matter of opinion.

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.

(Edited for clarity)


That depends. When you're doing simple translations the list way is much cleaner.

   ids = [item.id for item in all_items]
Seems much cleaner than

   ids = map(lambda item: item.id, all_items)
But yes, I agree, when you have to actually perform some less-than-trivial computation on every item of a list, map is much cleaner.


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!


why doesn't python have anonymous functions (not just lambdas which can only be expressions)?


Syntax. Strict indentation rules do not allow using a block of code in an expression.


It lets you define functions on the fly and use them, so the only difference from anonymous functions is that you have to pick a name.


Yeah, I almost wish they didn't use the keyword 'lambda' at all. If you could just write:

    def foo(x):
        def lambda():
          print x
        lambda;bar(callback=lambda);baz(42,lambda)
        def lambda():
          print x * x
        lambda;bar(callback=lambda);baz(42,lambda)
It'd stop this silly complaint. I just end up using 'def lambduh'

Slightly annoying that you need to define the function on the line before, can't inline it, but not nearly as bad as people make it out to be.


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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: