Beginning Python - From Novice to Professional

Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional

16.01.2014 Views

CHAPTER 6 ■ ABSTRACTION 135 >>> numbers = [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] >>> filter(lambda n: n % 2 == 0, numbers) [72, 108, 108, 44, 32, 114, 108, 100] The lambda expression simply checks whether the remainder of a given number when divided by 2 is zero (which is another way of saying that the number is even). Now, map and filter can be very useful, but they were added to the language before list comprehension came along. If you think about it, anything that map and filter can accomplish can also be done with list comprehensions: >>> [chr(n) for n in numbers] # characters corresponding to numbers ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'] >>> [ord(c) for c in 'Hello, world!'] # numbers corresponding to characters [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] >>> [n for n in numbers if n % 2 == 0] # filters out the odd numbers [72, 108, 108, 44, 32, 114, 108, 100] In my opinion, list comprehensions are, in most cases, more readable than using map and filter. I won’t go so far as to say that you always should use list comprehensions: it’s largely a matter of taste, and the demands of each specific programming task. ■Note If it is speed you are after, you may want to go with map and filter after all. When used with builtin functions, they are faster than list comprehensions. reduce But what about the third function, reduce? This is a tricky one, and I confess that I rarely use it. But people used to functional programming may find it useful. It combines the first two elements of a sequence with a given function, and combines the result with the third element, and so on until the entire sequence has been processed and a single result remains. For example, if you wanted to sum all the numbers of a sequence, you could use reduce with lambda x, y: x+y (still using the same numbers): 2 >>> numbers = [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] >>> reduce(lambda x, y: x+y, numbers) 1161 In this example, all the numbers of numbers are summed by successively adding the current sum and the next number in the sequence. What actually happens is very close to this: sum = 0 for number in numbers: sum = sum + number 2. Actually, instead of this lambda function, you could import the function add from the operator module, which has a function for each of the built-in operators. Using functions from the operator module is always more efficient than using your own functions.

136 CHAPTER 6 ■ ABSTRACTION In the original example, reduce takes care of the sum and the looping, while the lambda represents the expression sum + number. Let’s take a peek at what’s happening. The following defines a function for adding numbers that also prints out its arguments: def peek_sum(x, y): print 'Adding', x, 'and', y return x + y Let’s use this with reduce: >>> reduce(peek_sum, [1, 2, 3, 4, 5]) Adding 1 and 2 Adding 3 and 3 Adding 6 and 4 Adding 10 and 5 15 What happens is that reduce first adds 1 and 2, then adds the result with 3, and so on until all the elements have been added. Finally, after printing out all the operations it goes through, the sum (15) is returned. ■Note There is a built-in function called sum, which returns the sum of a sequence. (It cannot be used to join a sequence of strings.) As another example, let’s imagine that you could only use max with two arguments (in fact, it works with entire sequences) and you wanted to use it on a sequence. Then you could use reduce: >>> reduce(max, numbers) 119 The max function is used here to return the maximum of two numbers, and instead of keeping track of a sum, reduce keeps track of the maximum so far. Let’s take another peek under the hood: def peek_max(x, y): print 'Finding max of', x, 'and', y return max(x, y) Just like peek_sum, peek_max prints out its arguments when it is executed. Let’s use it with reduce: >>> reduce(peek_max, [3, 5, 2, 6, 9, 2]) Finding max of 3 and 5 Finding max of 5 and 2 Finding max of 5 and 6 Finding max of 6 and 9 Finding max of 9 and 2 9

136 CHAPTER 6 ■ ABSTRACTION<br />

In the original example, reduce takes care of the sum and the looping, while the lambda<br />

represents the expression sum + number. Let’s take a peek at what’s happening. The following<br />

defines a function for adding numbers that also prints out its arguments:<br />

def peek_sum(x, y):<br />

print 'Adding', x, 'and', y<br />

return x + y<br />

Let’s use this with reduce:<br />

>>> reduce(peek_sum, [1, 2, 3, 4, 5])<br />

Adding 1 and 2<br />

Adding 3 and 3<br />

Adding 6 and 4<br />

Adding 10 and 5<br />

15<br />

What happens is that reduce first adds 1 and 2, then adds the result with 3, and so on until<br />

all the elements have been added. Finally, after printing out all the operations it goes through,<br />

the sum (15) is returned.<br />

■Note There is a built-in function called sum, which returns the sum of a sequence. (It cannot be used <strong>to</strong><br />

join a sequence of strings.)<br />

As another example, let’s imagine that you could only use max with two arguments (in fact, it<br />

works with entire sequences) and you wanted <strong>to</strong> use it on a sequence. Then you could use reduce:<br />

>>> reduce(max, numbers)<br />

119<br />

The max function is used here <strong>to</strong> return the maximum of two numbers, and instead of<br />

keeping track of a sum, reduce keeps track of the maximum so far. Let’s take another peek<br />

under the hood:<br />

def peek_max(x, y):<br />

print 'Finding max of', x, 'and', y<br />

return max(x, y)<br />

Just like peek_sum, peek_max prints out its arguments when it is executed. Let’s use it<br />

with reduce:<br />

>>> reduce(peek_max, [3, 5, 2, 6, 9, 2])<br />

Finding max of 3 and 5<br />

Finding max of 5 and 2<br />

Finding max of 5 and 6<br />

Finding max of 6 and 9<br />

Finding max of 9 and 2<br />

9

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!