Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS 195 Finally, at the end of the function, add return result Although this may not work with all generators, it works with most. (For example, it fails with infinite generators, which of course can’t stuff their values into a list.) Here is the flatten generator rewritten as a plain function: def flatten(nested): result = [] try: # Don't iterate over string-like objects: try: nested + '' except TypeError: pass else: raise TypeError for sublist in nested: for element in flatten(sublist): result.append(element) except TypeError: result.append(nested) return result The Eight Queens Now that you’ve learned about all this magic, it’s time to put it to work. In this section, you see how to use generators to solve a classic programming problem. Generators are ideal for complex recursive algorithms that gradually build a result. Without generators, these algorithms usually require you to pass a half-built solution around as an extra parameter so that the recursive calls can build on it. With generators, all the recursive calls have to do is yield their part. That is what I did with the preceding recursive version of flatten, and you can use the exact same strategy to traverse graphs and tree structures. GRAPHS AND TREES If you have never heard of graphs and trees before, you ought to learn about them as soon as possible; they are very important concepts in programming and computer science. To find out more, you should probably get a book about computer science, discrete mathematics, data structures, or algorithms. For some concise definitions, you can check out the following Web pages: • http://mathworld.wolfram.com/Graph.html • http://mathworld.wolfram.com/Tree.html • http://www.nist.gov/dads/HTML/tree.html • http://www.nist.gov/dads/HTML/graph.html A quick Web search ought to turn up a lot of material.
196 CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS Backtracking In some applications, however, you don’t get the answer right away; you have to try several alternatives. And not only do you have to try several alternatives on one level, but on every level in your recursion. To draw a parallel from real life, imagine that you have an important meeting to go to. You’re not sure where it is, but you have two doors in front of you, and the meeting room has to be behind one of them. You choose the left, and step through. There you face another two doors. You choose the left, but it turns out to be wrong. So you backtrack, and choose the right door, which also turns out to be wrong (excuse the pun). So, you backtrack again, to the point where you started, ready to try the right door there. This strategy of backtracking is useful for solving problems that require you try every combination until you find a solution. Such problems are solved like this: # Pseudocode for each possibility at level 1: for each possibility at level 2: ... for each possibility at level n: is it viable? To implement this directly with for loops, you have to know how many levels you’ll encounter. If that is not possible, you use recursion. The Problem This is a much loved computer science puzzle: You have a chessboard, and eight queen pieces to place on it. The only requirement is that none of the queens threatens any of the others; that is, you must place them so that no two queens can capture each other. How do you do this? Where should the queens be placed? This is a typical backtracking problem: you try one position for the first queen (in the first row), advance to the second, and so on. If you find that you are unable to place a queen, you backtrack to the previous one and try another position. Finally, you either exhaust all possibilities, or find a solution. In the problem as stated, you are provided with information that there will be only eight queens, but let’s assume that there can be any number of queens. (This is more similar to realworld backtracking problems.) How do you solve that? If you want to try to solve it yourself, you should stop reading now because I’m about to give you the solution. ■Note There are, in fact, much more efficient solutions available for this problem. If you want more details, a Web search should turn up a wealth of information. A brief history of various solutions may be found at http://www.cit.gu.edu.au/~sosic/nqueens.html. State Representation To represent a possible solution (or part of it), you can simply use a tuple (or a list, for that matter). Each element of the tuple indicates the position (that is, column) of the queen of the
- 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
- Page 214 and 215: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 216 and 217: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 218 and 219: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 220 and 221: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 222 and 223: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 224 and 225: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 228 and 229: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 230 and 231: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 232 and 233: CHAPTER 9 ■ MAGIC METHODS, PROPER
- Page 234 and 235: CHAPTER 10 ■ ■ ■ Batteries In
- Page 236 and 237: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 238 and 239: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 240 and 241: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 242 and 243: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 244 and 245: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 246 and 247: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 248 and 249: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 250 and 251: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 252 and 253: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 254 and 255: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 256 and 257: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 258 and 259: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 260 and 261: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 262 and 263: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 264 and 265: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 266 and 267: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 268 and 269: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 270 and 271: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 272 and 273: CHAPTER 10 ■ BATTERIES INCLUDED 2
- Page 274 and 275: CHAPTER 10 ■ BATTERIES INCLUDED 2
CHAPTER 9 ■ MAGIC METHODS, PROPERTIES, AND ITERATORS 195<br />
Finally, at the end of the function, add<br />
return result<br />
Although this may not work with all genera<strong>to</strong>rs, it works with most. (For example, it fails<br />
with infinite genera<strong>to</strong>rs, which of course can’t stuff their values in<strong>to</strong> a list.)<br />
Here is the flatten genera<strong>to</strong>r rewritten as a plain function:<br />
def flatten(nested):<br />
result = []<br />
try:<br />
# Don't iterate over string-like objects:<br />
try: nested + ''<br />
except TypeError: pass<br />
else: raise TypeError<br />
for sublist in nested:<br />
for element in flatten(sublist):<br />
result.append(element)<br />
except TypeError:<br />
result.append(nested)<br />
return result<br />
The Eight Queens<br />
Now that you’ve learned about all this magic, it’s time <strong>to</strong> put it <strong>to</strong> work. In this section, you see<br />
how <strong>to</strong> use genera<strong>to</strong>rs <strong>to</strong> solve a classic programming problem.<br />
Genera<strong>to</strong>rs are ideal for complex recursive algorithms that gradually build a result. Without<br />
genera<strong>to</strong>rs, these algorithms usually require you <strong>to</strong> pass a half-built solution around as an extra<br />
parameter so that the recursive calls can build on it. With genera<strong>to</strong>rs, all the recursive calls<br />
have <strong>to</strong> do is yield their part. That is what I did with the preceding recursive version of flatten,<br />
and you can use the exact same strategy <strong>to</strong> traverse graphs and tree structures.<br />
GRAPHS AND TREES<br />
If you have never heard of graphs and trees before, you ought <strong>to</strong> learn about them as soon as possible; they<br />
are very important concepts in programming and computer science. To find out more, you should probably get<br />
a book about computer science, discrete mathematics, data structures, or algorithms. For some concise definitions,<br />
you can check out the following Web pages:<br />
• http://mathworld.wolfram.com/Graph.html<br />
• http://mathworld.wolfram.com/Tree.html<br />
• http://www.nist.gov/dads/HTML/tree.html<br />
• http://www.nist.gov/dads/HTML/graph.html<br />
A quick Web search ought <strong>to</strong> turn up a lot of material.