I sing the praises of lambda, my friend and savior!

Clark C. Evans cce at clarkevans.com
Mon Oct 11 19:54:29 CEST 2004

On Mon, Oct 11, 2004 at 04:58:27PM +0000, Steven Bethard wrote:
| Clark C. Evans wrote:
| >    def somerandomname(args):
| >        body
| >    func(arg, somerandomname)
| > 
| > So, you've taken something that is a perfectly clear one-liner and
| > converted it into a 3 line chunk of code with _zero_ added clarity,
| > in fact, I'd say you've dramatically reduced clarity by requiring
| > the a name be 'minted'.
| The argument that was given to me is that, if I wrote my def statement
| as a general enough function, I could reuse the function at multiple 
| points in the code.

By this logic, one would make a function,

  def quadratic(a,b,c):
      def eval(x):
          return a*x*x+b*x+c

and use quadratic(0,2,1,x) where you'd otherwise write (2*x+1)?
Then, it follows that for lazy-evaluation cases, you'd write,

   func(arg, quadratic(0,2,1))

insead of the more succinct,

   func(arg, lambda x: 2*x+1)

Trying to 'generalize', aka 'normalize everything' on one or two use
cases dramatically bloats code size and, contrary to what one would
believe, makes things much less understandable.

For example, Guido is also in favor of dropping reduce/map and other
"generic functions" beacuse list comprehensions do a much better job
at expressing intent.  In my opinion, lambda is more like list 
comprehensions (a succinct syntax for a common idiom) than it 
is like these other functional parts of Python.

| This was mostly true for me, but there are some styles of code that I 
| don't write too much (e.g. event-driven) so I can imagine that this 
| might not be as applicable to others...

Lazy evaulation, currying, and other similar cases need some sort
of anonymous block.  Those same people who would take lambda away
from me, are the same ones that freak out when they see this:

   { 'one': 1, 'two': 2 }.get(x, None)

as they'd rather write it as a bunch of if/then statements (*gags*).

| I think the point was to have full-fledged anonymous functions, 
| instead of lambdas, which are restricted to a single expression. 

I don't mind this "limitation" of lambda.  In a way, it makes a nice
boundary condition, if you have so much logic in your expression
that you need a statement especially a loop -- perhaps you do have a
real-live code block that should be named and documented.

That said, a simple conditional expression would be delightful, as 
I often use mappings (see above) for this sort of logic.

| Of course, the syntax chosen for this is (to some degree, 
| at least) arbitrary, but the idea would be to allow things like:
| func(arg1, lambda arg2:
|                self.update(arg2)hose 
|                return arg2*2)

A dirty trick for this case,

    lambda arg2: (self.update(arg2),arg2*2)[-1]

    def last(*args):
        return args[-1]

    func(arg1,lambda arg2: last(self.update(arg2),arg2*2))

In this case I _do_ use a function called last in my code,
since it is indeed generic, reusable, and therefore should
be given a name.

| My understanding is that no one's ever found an anonymous def
| syntax that everyone really likes, so I suspect the argument will
| continue to be "too ugly for too little gain in coding ease".
| Especially since as soon as you really do need a multiline def, it
| only costs you one line to declare the function normally, and you
| don't get funny indentation:
| def foo(arg2):
|     self.update(arg2)
|     return arg2*2
| func(arg1, foo)

Besides being a succinct syntax, what is essential about the lambda
construct is that it doesn't introduce a name.  I don't have to find
a name, nor do I have to worry about name collisions, nor to I have
to worry that the function is being used somewhere else.  



More information about the Python-list mailing list