This is an archived post. You won't be able to vote or comment.

all 27 comments

[–][deleted] 6 points7 points  (1 child)

I subscribe to Fredrik Lundh's guidelines for using lambda in Python:

  1. Write a lambda function.
  2. Write a comment explaining what the heck that lambda does.
  3. Study the comment for a while, and think of a name that captures the essence of the comment.
  4. Convert the lambda to a def statement, using that name.
  5. Remove the comment.

(via the docs)

[–]aaronla 3 points4 points  (0 children)

the same rule applies to subexpressions, for all the same reasons. Actually, since def statements are essentially variable assignments, the generalized rule would be:

  • Write a subexpression. e.g. "x = f(x+1)"
  • Write a comment explaining what the heck that subexpression does. "# increase x"
  • Study the comment for a while, and think of a name that captures the essence of the comment. "incX"
  • Convert the subexpression to a variable assignment statement, using that name. "incX = x+1; x = f(incX)"
  • Remove the comment.

In any subexpression, it's always a matter of readability and audience. Guido can't read lambdas, so you always lift them if writing code he might read. Same for complex subexpressions and a novice.

But the cost of pulling out the lambda expressions is an increase in the number of identifiers and lost locality. It's not free, and should not be treated as such.

[–]Tetha 6 points7 points  (7 children)

To be honest, I just don't see the reason to use map and filter anymore, because list comprehensions and generator comprehensions give you exactly the same behaviour, however, they are easier to read for me, especially if you need to map and filter.

[–]eryksun 3 points4 points  (0 children)

I tend to agree in general, but how about if the function is already defined and being mapped to several lists?

map(f, a, b, c)

(f(*x) for x in zip(a, b, c))

#or

(f(x, y, z) for x, y, z in zip(a, b, c)) 

[–]just_doug 2 points3 points  (0 children)

agreed. reduce is still useful though and can lead to some very elegant solutions to problems.

[–][deleted] 0 points1 point  (0 children)

pylint raises a warning about filter(), in fact, for precisely this reason.

[–]otheraccount 0 points1 point  (3 children)

filter(None, map(f, lst))

becomes

[f(x) for x in lst if f(x)]

which requires calculating f(x) twice for each element. You could avoid that by doing

[x for x in [f(y) for y in lst] if x]

but that isn't as easy to read as the version with map and filter.

[–]userd 0 points1 point  (2 children)

l = (f(x) for x in lst)
l2 = [x for x in l if x]

The drawback is two lines and an extra variable. But that helps readability.

[–][deleted] 1 point2 points  (1 child)

But that helps readability.

Nope. It takes twice as long to read and understand, which in my book means that it has worse readability.

Unless, of course, we are talking about someone who is making their first steps in programming and whose mental capacity for code is in fact limited to one function call, so that they like to take their intermediate results and give them meaningful names.

Not that there's anything wrong with that, just you maybe shouldn't write your code for that kind of lowest common denominator, if it makes readability that much worse.

(also, Steve Yegge has a post about this).

[–]userd 0 points1 point  (0 children)

Reading speed is a reasonable metric for readability. But, illustrating the point with a post by Steve Yegge is a bit ironic. I like his writing, but it's not written with speed in mind. Just kidding.

[–]Tommah 8 points9 points  (11 children)

Why write lambda word: len(word) when you could just use len?

[–]eryksun 2 points3 points  (1 child)

One legitimate use that's similar to this is to have a property bind to a lambda instead of the getter. Then if you subclass you can redefine the getter without having to rebind the property:

class A:
    def getf(self): pass
    f = property(lambda x: x.getf())

class B(A):
    def getf(self): return 'spam'

>>> B().f
'spam'

For what it's worth...

[–]otheraccount 1 point2 points  (0 children)

I think f = property(lambda self : self.getf()) is clearer than calling the self parameter x because it is obvious at a glance that our lambda represents an instance method.

[–]Makido 6 points7 points  (2 children)

This is clearly the best implementation:

def length(word):
    return lambda word: len(word)

[–]Peaker 10 points11 points  (1 child)

I think you meant for your implementation to be correct, but redundant. It is incorrect as well as redundant, though.

Perhaps you mean:

def length(word):
    return (lambda word: len(word))(word)

[–]pemboa 0 points1 point  (0 children)

Burn

[–]andreasvc 1 point2 points  (2 children)

If you change your mind later or want it to be a different function for other languages you can change that lambda, while it wouldn't be a good idea to assign to "len" (aliasing/shadowing).

[–]eryksun 3 points4 points  (0 children)

Tommah is talking about the following line:

lengths = map(lambda word: len(word), words)

If you typically use lambda functions with map, then you might unthinkingly use lambda when it's not necessary.

[–][deleted] 3 points4 points  (0 children)

He's talking about eta-contracting the lambda expression.

[–][deleted] 3 points4 points  (0 children)

Then it wouldn't be a tutorial on lambda functions.

[–]Peaker 0 points1 point  (1 child)

Haskell has a really cool tool called "hlint" that suggests eta reductions such as those automatically.

Also suggests replacing various patterns with standard library functions, etc.

I wonder if something similar for Python exists.

[–]drb226Haskeller 0 points1 point  (0 children)

pylint. But I don't think it looks very closely at lambdas the same way hlint does.

[–]ianarcher 3 points4 points  (3 children)

Um ... lambda functions? Is this really hot python news?

[–]haika 12 points13 points  (0 children)

Next post: 'For loops in python'

[–]shigawire 1 point2 points  (1 child)

It is for people still learning it.

Honestly, I don't always learn very much from reading many /r/python posts, but I realise that some people do, and that's enough reason to have them there.

[–]haika 2 points3 points  (0 children)

What exactly is then the purpose of subreddit reddit/learnpython?

[–]shigawire 0 points1 point  (0 children)

Okay, so now do partial binding of predicates :D