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.

Recommended Answers

All 6 Replies

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 for Enalicho

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)

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

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 ?)

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()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.