1,105,331 Community Members

What the Lambda?

Member Avatar
pyguy62
Posting Whiz
346 posts since Aug 2011
Reputation Points: 23 [?]
Q&As Helped to Solve: 19 [?]
Skill Endorsements: 0 [?]
 
0
 

so I recently wrote a function that sorted using the last value in a tuple. Obviously this couldn't be done simply say sorted(tuples, key=tuples[-1]) because that is not a "legal" call. However I did run across, while trying to figure out how to make things like this work, the utilization of lambda so the code became.

def sort_last(tuples):
    x=sorted(tuples, key=lambda tuples: tuples[-1])
    return(x)

The code runs correctly and, that's all well and good, but I don't understand why lambda tuples"or any given var for that matter":. makes this possible. Can someone explain this to me in a way I'll understand so that I can utilize the principle to its maximum potential?
p.s. I have essentially no calculus experience.

Member Avatar
Gribouillis
Posting Maven
3,452 posts since Jul 2008
Reputation Points: 1,140 [?]
Q&As Helped to Solve: 883 [?]
Skill Endorsements: 18 [?]
Moderator
 
0
 

Well, writing

key = lambda x, y, z: expression(x, y, z)

has the same effect as

def dummy(x, y, z):
    return expression(x, y, z)

key = dummy

It means that lambda is only a way to write small, anonymous functions. The main restriction is that the body of a lambda form is not a sequence of statements but a single python expression (note that the keyword 'return' does not appear in the lambda form).

Lambda forms come from a branch of mathematical logic called "lambda calculus" which studies the logical consequences of an abstract functional language. These lambda forms are the basis of most so-called functional programming languages and that's where python borrowed the construct (together with list comprehensions and generators).

I tend to believe that lambda forms are not very useful in python. Writing a genuine small function is not less efficient and it is more flexible (it leaves the possibility to add statements in the body, if only a print or assert statement for debugging).

Member Avatar
Enalicho
Junior Poster in Training
62 posts since Aug 2011
Reputation Points: 14 [?]
Q&As Helped to Solve: 13 [?]
Skill Endorsements: 0 [?]
 
0
 

I disagree. lambda functions are very handy, for example -

>>> numbers = [1,2,3,4,5]
>>> map(lambda x:x+1, numbers)
[2, 3, 4, 5, 6]
>>> reduce(lambda x,y: x+y, numbers)
15
>>> filter(lambda x: x%2==0, numbers)
[2, 4]
>>> def a(x):
...     return lambda y: y+x
...
>>> add_three = a(3)
>>> add_three(1)
4
>>> sorted(numbers,key=lambda x: x%2)
[2, 4, 1, 3, 5]

It is also _very_ heavily used in GUI development, as events (scrolling, etc). Of course, if you can use a list comp instead of these, then do so. They're usually more readable.

IMO, if you assign lambda to something, it shouldn't be used, instead you should define a method using def. In production code, use it where it's useful, but try to use it as little as possible (don't assign it to a name)

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
0
 

Lambda is usefull, sometimes it is nicer to replace it with proper function or use functools.partial instead.

Say if you wanted to sort strings so that the sort is case insensitive and words starting with x come first instead of normal place (but x inside the string behave normally)

def xfirst_key(xword):
    xword = xword.lower()
    return (not xword.startswith('x'), xword)    

notinorder = ['mix', 'xyz', '', 'Apple', 'Xanadu', 'aardvark', 'min']
print(sorted(notinorder, key=lambda x: (not x.startswith(('x','X')), x.lower())))
print(sorted(notinorder, key=lambda x: (x and x[0] not in 'xX', x.lower())))
print(sorted(notinorder, key=xfirst_key))
Member Avatar
Gribouillis
Posting Maven
3,452 posts since Jul 2008
Reputation Points: 1,140 [?]
Q&As Helped to Solve: 883 [?]
Skill Endorsements: 18 [?]
Moderator
 
0
 

Lambda is usefull, sometimes it is nicer to replace it with proper function or use functools.partial instead.

Say if you wanted to sort strings so that the sort is case insensitive and words starting with x come first instead of normal place (but x inside the string behave normally)

def xfirst_key(xword):
    xword = xword.lower()
    return (not xword.startswith('x'), xword)    

notinorder = ['mix', 'xyz', '', 'Apple', 'Xanadu', 'aardvark', 'min']
print(sorted(notinorder, key=lambda x: (not x.startswith(('x','X')), x.lower())))
print(sorted(notinorder, key=lambda x: (x and x[0] not in 'xX', x.lower())))
print(sorted(notinorder, key=xfirst_key))

It's a typical example. I think the last version is far better. Lambda is cryptic.

Also, about

sorted(numbers,key=lambda x: x%2)

it's very difficult to guess what the sort does if you didn't write this code yourself. I prefer

def even_first_score(x):
    return x % 2

print( sorted(numbers, key = even_first_score) )

or a similar name.

Also note that map, reduce and filter are condemned by Van Rossum himself (ever read this www.python.org/doc/essays/ppt/regrets/PythonRegrets.pdf ?)

Member Avatar
pyTony
pyMod
6,103 posts since Apr 2010
Reputation Points: 818 [?]
Q&As Helped to Solve: 1,056 [?]
Skill Endorsements: 42 [?]
Moderator
Featured
 
1
 

Here the example with functools.partial examples for general function and button call backs added. Clear names are absolute must, but sometimes descriptive docstring is better than too long name, which is still unclear. Notice that in ide like IDLE, you get tooltip of first line of docstring, when you type functions name.

from functools import partial
import string
from Tkinter import *

def exceptions_key(word, exceptional):
    """ exceptional first, then others, first empty string, however.

    """
    word = word.lower()
    order = exceptional.lower()+ ''.join(c for c in string.lowercase)
    return (not word and -1) or order.find(word[0]), word

def xfirst_key(xword):
    xword = xword.lower()
    return (not xword.startswith('x'), xword)    

def number_to_title(root, number):
    root.title('%s pushed' % number)

notinorder = ['mix', 'xyz', '', 'Apple', 'Xanadu', 'aardvark', 'min', 'sun']
print(sorted(notinorder, key=lambda x: (not x.startswith(('x','X')), x.lower())))
print(sorted(notinorder, key=lambda x: (x and x[0] not in 'xX', x.lower())))
print(sorted(notinorder, key=xfirst_key))
# both x and m exceptions
print(sorted(notinorder, key=partial(exceptions_key, exceptional='xm')))

root = Tk()
for i in range(1,20):
    Button(text=str(i),
           command=partial(number_to_title,
                           root=root, number=i)).pack(side=LEFT, padx=4, pady=4)
root.mainloop()
Member Avatar
nabla2
Newbie Poster
12 posts since Aug 2011
Reputation Points: 13 [?]
Q&As Helped to Solve: 4 [?]
Skill Endorsements: 0 [?]
 
1
 

Fresh presentation about lambda expressions: Newbie Nugget: Lambda Expressions

You
This article has been dead for over three months: Start a new discussion instead
Post:
Start New Discussion
View similar articles that have also been tagged: