next up previous contents
Next: Using Modules Up: Functions Previous: Variable Number of Arguments   Contents

Functional Programming, and anonymous functions

When you have a list of objects, and need to perform the same task on each of the objects, an alternative to using a for loop is to use the map function. This function accepts a function as its first argument, and one or more lists as additional arguments. The number of lists which are provided as additional arguments must be equal to the number of arguments which the function being mapped requires.

To illustrate, suppose we have a list of first names and a second list of last names, and we wish to produce a list each of whose elements is a first name joined with its corresponding last name. Using the join function of the string module, we could do this with a for loop

>>> first = ['Joe','Sue','Harry']
>>> last = ['Smith','Williams','Brown']
>>> both = []
>>> for i in range(0,len(first)):
...     both.append(string.join([first[i],last[i]],' '))
>>> both
['Joe Smith', 'Sue Williams', 'Harry Brown']

But by defining a function to combine the two pieces, we could achieve the same goal more simply using map:

>>> def joinname(first,last):
...     return string.join([first,last],' ')     
>>> map(joinname,first,last)
['Joe Smith', 'Sue Williams', 'Harry Brown']
Notice that the names first and last have different meanings inside and outside the function.

In situations like this, when we are creating a function which will be used only once, Python provides the lambda operator to produce what are known as anonymous functions. Anonymous functions are limited to a single statement which becomes the value returned by the lambda operator. Instead of listing the arguments to the lambda operator in parentheses, you just follow the word lambda with a comma separated list of arguments. Our previous example could then be simplified to:

>>> map(lambda first,last:string.join([first,last],' '),first,last)
['Joe Smith', 'Sue Williams', 'Harry Brown']

When the first argument to map is the special Python object None, map simply returns whatever arguments it is passed. This provides a simple way to turn two lists into a single list consisting of (tuple) pairs of corresponding elements. Thus if we use None as the first argument to map in the previous example, we get a list containing pairs of first and last names:

>>> map(None,first,last)
[('Joe', 'Smith'), ('Sue', 'Williams'), ('Harry', 'Brown')]

Another functional programming tool provided by Python is the filter function. Like, map, the first argument to filter is a function, and the second argument is a list, but filter returns a new list containing only those elements of the list for which the function returns a value of true. For example, to eliminate negative numbers from a list, we could use filter as follows:

>>> nums = [-3,7,12,-2,19,-5,7,8,-3]
>>> filter(lambda x:x > 0,nums)
[7, 12, 19, 7, 8]

You may recall the list comprehension (See Section 6.9) as an alternative way to evaluate an expression for all of the elements of a list. In fact, with a single for clause, a list comprehension is much like a similar call to map; by adding an if clause to the comprehension, it becomes much like embedding a call to filter inside a call to map, as this example shows:

>>> nums = [-4,7,8,3,-2,9]
>>> map(lambda x:x + 10,filter(lambda x:x > 0,nums))
[17, 18, 13, 19]
>>> [x + 10 for x in nums if x > 0]
[17, 18, 13, 19]
Some programmers prefer the list comprehension over map and filter because it eliminates the need for lambda functions.

When there is more than one for loop, corresponding to additional arguments in map, map requires a function which will take as many arguments as there are lists being processed, each of the same length, while the list comprehension simply evaluates its expression for every combination of values expressed by the for loops. Notice the difference between these two statements:

>>> map(lambda x,y:(x,y),['a','b','c'],['1','2','3'])
[('a', '1'), ('b', '2'), ('c', '3')]
>>> [(x,y) for x in ['a','b','c'] for y in ['1','2','3']]
[('a', '1'), ('a', '2'), ('a', '3'), ('b', '1'), ('b', '2'), 
 ('b', '3'), ('c', '1'), ('c', '2'), ('c', '3')]
In the previous example, the lengths of the two arguments passed to map for processing must be of the same size, but there is no similar restriction for the list comprehension.

Finally, the function reduce takes as its first argument a function with exactly two arguments, and as its second argument a list . It successively applies the function to the elements of the list, using the current result of the application as the first argument to the function, and one of the elements of the list as the second argument, and returns a scalar value. An optional third argument provides a starting value, which otherwise defaults to 0. Thus to take the sum of a list of numbers we could use the following:

>>> reduce(lambda x,y:x + y,nums)

next up previous contents
Next: Using Modules Up: Functions Previous: Variable Number of Arguments   Contents
Phil Spector 2003-11-12