Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 6 ■ ABSTRACTION 133 search recursively with new limits. You could even make this easier to use by making the limit specifications optional. You simply add the following conditional to the beginning of the function definition: def search(sequence, number, lower=0, upper=None): if upper is None: upper = len(sequence)-1 ... Now, if you don’t supply the limits, they are set to the first and last positions of the sequence. Let’s see if this works: >>> seq = [34, 67, 8, 123, 4, 100, 95] >>> seq.sort() >>> seq [4, 8, 34, 67, 95, 100, 123] >>> search(seq, 34) 2 >>> search(seq, 100) 5 But why go to all this trouble, you ask? For one thing, you could simply use the list method index, and if you wanted to implement this yourself, you could just make a loop starting at the beginning and iterating along until you found the number. Sure. Using index is just fine. But using a simple loop may be a bit inefficient. Remember I said you needed seven questions to find one number (or position) among 100? And the loop obviously needs 100 questions in the worst-case scenario. Big deal, you say. But if the list has 100,000,000,000,000,000,000,000,000,000,000,000 elements, and the same number of questions with a loop (perhaps a somewhat unrealistic size for a Python list), this sort of thing starts to matter. Binary search would then need only 117 questions. Pretty efficient, huh? ■Tip There is a standard library module called bisect, which implements binary search very efficiently. Throwing Functions Around By now, you are probably used to using functions just like other objects (strings, number, sequences, and so on) by assigning them to variables, passing them as parameters, and returning them from other functions. Some programming languages (such as Scheme or LISP) use functions in this way to accomplish almost everything. Even though you usually don’t rely that heavily on functions in Python (you usually make your own kinds of objects—more about that in the next chapter), you can. This section describes a few functions that are useful for this sort of “functional programming.” These functions are map, filter, reduce, and apply.
134 CHAPTER 6 ■ ABSTRACTION LAMBDA EXPRESSIONS In the material that follows, I sometimes use something called lambda expressions. These are small, unnamed functions that can only contain an expression, and that return its value. A lambda expression is written like this: lambda x, y, z: x + y + z The first word, lambda, is a reserved word (keyword). 1 It is followed by the parameters, a colon (:), and finally the body (an expression). Although lambdas can be useful at times, you are usually better off writing a full-fledged function, especially because the function name will then say something about what your function does. map The map function “maps” one sequence into another (of the same length) by applying a function to each of the elements. For example, you may have a list of numbers, and you want to create another list in which all the numbers are doubled: >>> numbers = [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] >>> map(lambda n: 2*n, numbers) [144, 202, 216, 216, 222, 88, 64, 238, 222, 228, 216, 200, 66] You don’t have to use lambda expressions—it works just fine with named functions as well: >>> map(chr, numbers) ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!'] The built-in function chr takes a number as its only parameter and returns the character corresponding to that number (the so-called ordinal number, which is really its ASCII code). The reverse of chr is ord: >>> map(ord, 'Hello, world!') [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33] Because strings are just sequences of characters, you can use map directly. Note that the result is a list, not another string. See the following section for a note about map, filter, and list comprehensions. filter The filter function returns a new list in which the elements that you don’t want have been filtered out. Or, to put it another way, it returns exactly those you do want. You supply filter with a function that returns a Boolean (truth) value for a given sequence element. If the function returns true, the element is part of the returned sequence; if it returns false, the element is not included in the returned sequence. (The original sequence is not modified.) For example, you might want to retain only the even numbers from the list numbers: 1. The name “lambda” comes from the Greek letter λ, which is used in mathematics to indicate an anonymous function.
- Page 113 and 114: 82 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 115 and 116: 84 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 117 and 118: 86 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 119 and 120: 88 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 121 and 122: 90 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 123 and 124: 92 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 125 and 126: 94 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 127 and 128: 96 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 129 and 130: 98 CHAPTER 5 ■ CONDITIONALS, LOOP
- Page 131 and 132: 100 CHAPTER 5 ■ CONDITIONALS, LOO
- Page 133 and 134: 102 CHAPTER 5 ■ CONDITIONALS, LOO
- Page 135 and 136: 104 CHAPTER 5 ■ CONDITIONALS, LOO
- Page 137 and 138: 106 CHAPTER 5 ■ CONDITIONALS, LOO
- Page 139 and 140: 108 CHAPTER 5 ■ CONDITIONALS, LOO
- Page 141 and 142: 110 CHAPTER 6 ■ ABSTRACTION But w
- Page 143 and 144: 112 CHAPTER 6 ■ ABSTRACTION ■Ti
- Page 145 and 146: 114 CHAPTER 6 ■ ABSTRACTION Can I
- Page 147 and 148: 116 CHAPTER 6 ■ ABSTRACTION stora
- Page 149 and 150: 118 CHAPTER 6 ■ ABSTRACTION 4. Yo
- Page 151 and 152: 120 CHAPTER 6 ■ ABSTRACTION The p
- Page 153 and 154: 122 CHAPTER 6 ■ ABSTRACTION >>> p
- Page 155 and 156: 124 CHAPTER 6 ■ ABSTRACTION Also,
- Page 157 and 158: 126 CHAPTER 6 ■ ABSTRACTION Feel
- Page 159 and 160: 128 CHAPTER 6 ■ ABSTRACTION ■No
- Page 161 and 162: 130 CHAPTER 6 ■ ABSTRACTION So yo
- Page 163: 132 CHAPTER 6 ■ ABSTRACTION numer
- Page 167 and 168: 136 CHAPTER 6 ■ ABSTRACTION In th
- Page 169 and 170: 138 CHAPTER 6 ■ ABSTRACTION Scope
- Page 171 and 172: 140 CHAPTER 7 ■ MORE ABSTRACTION
- Page 173 and 174: 142 CHAPTER 7 ■ MORE ABSTRACTION
- Page 175 and 176: 144 CHAPTER 7 ■ MORE ABSTRACTION
- Page 177 and 178: 146 CHAPTER 7 ■ MORE ABSTRACTION
- Page 179 and 180: 148 CHAPTER 7 ■ MORE ABSTRACTION
- Page 181 and 182: 150 CHAPTER 7 ■ MORE ABSTRACTION
- Page 183 and 184: 152 CHAPTER 7 ■ MORE ABSTRACTION
- Page 185 and 186: 154 CHAPTER 7 ■ MORE ABSTRACTION
- Page 187 and 188: 156 CHAPTER 7 ■ MORE ABSTRACTION
- Page 189 and 190: 158 CHAPTER 7 ■ MORE ABSTRACTION
- Page 191 and 192: 160 CHAPTER 8 ■ EXCEPTIONS >>> im
- Page 193 and 194: 162 CHAPTER 8 ■ EXCEPTIONS Custom
- Page 195 and 196: 164 CHAPTER 8 ■ EXCEPTIONS More T
- Page 197 and 198: 166 CHAPTER 8 ■ EXCEPTIONS try: x
- Page 199 and 200: 168 CHAPTER 8 ■ EXCEPTIONS Invali
- Page 201 and 202: 170 CHAPTER 8 ■ EXCEPTIONS If you
- Page 204 and 205: CHAPTER 9 ■ ■ ■ Magic Methods
- Page 206 and 207: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 208 and 209: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 210 and 211: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 212 and 213: CHAPTER 9 ■ MAGIC METHODS, PROPER
CHAPTER 6 ■ ABSTRACTION 133<br />
search recursively with new limits. You could even make this easier <strong>to</strong> use by making the limit<br />
specifications optional. You simply add the following conditional <strong>to</strong> the beginning of the<br />
function definition:<br />
def search(sequence, number, lower=0, upper=None):<br />
if upper is None: upper = len(sequence)-1<br />
...<br />
Now, if you don’t supply the limits, they are set <strong>to</strong> the first and last positions of the sequence.<br />
Let’s see if this works:<br />
>>> seq = [34, 67, 8, 123, 4, 100, 95]<br />
>>> seq.sort()<br />
>>> seq<br />
[4, 8, 34, 67, 95, 100, 123]<br />
>>> search(seq, 34)<br />
2<br />
>>> search(seq, 100)<br />
5<br />
But why go <strong>to</strong> all this trouble, you ask? For one thing, you could simply use the list method<br />
index, and if you wanted <strong>to</strong> implement this yourself, you could just make a loop starting at the<br />
beginning and iterating along until you found the number.<br />
Sure. Using index is just fine. But using a simple loop may be a bit inefficient. Remember I<br />
said you needed seven questions <strong>to</strong> find one number (or position) among 100? And the loop<br />
obviously needs 100 questions in the worst-case scenario. Big deal, you say. But if the list has<br />
100,000,000,000,000,000,000,000,000,000,000,000 elements, and the same number of questions<br />
with a loop (perhaps a somewhat unrealistic size for a <strong>Python</strong> list), this sort of thing starts <strong>to</strong><br />
matter. Binary search would then need only 117 questions. Pretty efficient, huh?<br />
■Tip There is a standard library module called bisect, which implements binary search very efficiently.<br />
Throwing Functions Around<br />
By now, you are probably used <strong>to</strong> using functions just like other objects (strings, number,<br />
sequences, and so on) by assigning them <strong>to</strong> variables, passing them as parameters, and<br />
returning them from other functions. Some programming languages (such as Scheme or LISP)<br />
use functions in this way <strong>to</strong> accomplish almost everything. Even though you usually don’t rely<br />
that heavily on functions in <strong>Python</strong> (you usually make your own kinds of objects—more about<br />
that in the next chapter), you can. This section describes a few functions that are useful for this<br />
sort of “functional programming.” These functions are map, filter, reduce, and apply.