blob: 89f7a6dd247ea94be3444d63fb15e89a06b4de30 [file] [log] [blame]
Tim Peters6ba5f792001-06-23 20:45:43 +00001tutorial_tests = """
Tim Peters1def3512001-06-23 20:27:04 +00002Let's try a simple generator:
3
4 >>> def f():
5 ... yield 1
6 ... yield 2
7
Tim Petersb9e9ff12001-06-24 03:44:52 +00008 >>> for i in f():
9 ... print i
10 1
11 2
Tim Peters1def3512001-06-23 20:27:04 +000012 >>> g = f()
13 >>> g.next()
14 1
15 >>> g.next()
16 2
Tim Petersea2e97a2001-06-24 07:10:02 +000017
Tim Peters2106ef02001-06-25 01:30:12 +000018"Falling off the end" stops the generator:
Tim Petersea2e97a2001-06-24 07:10:02 +000019
Tim Peters1def3512001-06-23 20:27:04 +000020 >>> g.next()
21 Traceback (most recent call last):
22 File "<stdin>", line 1, in ?
23 File "<stdin>", line 2, in g
24 StopIteration
25
Tim Petersea2e97a2001-06-24 07:10:02 +000026"return" also stops the generator:
Tim Peters1def3512001-06-23 20:27:04 +000027
28 >>> def f():
29 ... yield 1
30 ... return
31 ... yield 2 # never reached
32 ...
33 >>> g = f()
34 >>> g.next()
35 1
36 >>> g.next()
37 Traceback (most recent call last):
38 File "<stdin>", line 1, in ?
39 File "<stdin>", line 3, in f
40 StopIteration
41 >>> g.next() # once stopped, can't be resumed
42 Traceback (most recent call last):
43 File "<stdin>", line 1, in ?
44 StopIteration
45
46"raise StopIteration" stops the generator too:
47
48 >>> def f():
49 ... yield 1
Tim Peters34463652001-07-12 22:43:41 +000050 ... raise StopIteration
Tim Peters1def3512001-06-23 20:27:04 +000051 ... yield 2 # never reached
52 ...
53 >>> g = f()
54 >>> g.next()
55 1
56 >>> g.next()
57 Traceback (most recent call last):
58 File "<stdin>", line 1, in ?
59 StopIteration
60 >>> g.next()
61 Traceback (most recent call last):
62 File "<stdin>", line 1, in ?
63 StopIteration
64
65However, they are not exactly equivalent:
66
67 >>> def g1():
68 ... try:
69 ... return
70 ... except:
71 ... yield 1
72 ...
73 >>> list(g1())
74 []
75
76 >>> def g2():
77 ... try:
78 ... raise StopIteration
79 ... except:
80 ... yield 42
81 >>> print list(g2())
82 [42]
83
84This may be surprising at first:
85
86 >>> def g3():
87 ... try:
88 ... return
89 ... finally:
90 ... yield 1
91 ...
92 >>> list(g3())
93 [1]
94
95Let's create an alternate range() function implemented as a generator:
96
97 >>> def yrange(n):
98 ... for i in range(n):
99 ... yield i
100 ...
101 >>> list(yrange(5))
102 [0, 1, 2, 3, 4]
103
104Generators always return to the most recent caller:
105
106 >>> def creator():
107 ... r = yrange(5)
108 ... print "creator", r.next()
109 ... return r
110 ...
111 >>> def caller():
112 ... r = creator()
113 ... for i in r:
114 ... print "caller", i
115 ...
116 >>> caller()
117 creator 0
118 caller 1
119 caller 2
120 caller 3
121 caller 4
122
123Generators can call other generators:
124
125 >>> def zrange(n):
126 ... for i in yrange(n):
127 ... yield i
128 ...
129 >>> list(zrange(5))
130 [0, 1, 2, 3, 4]
131
132"""
133
Tim Peters6ba5f792001-06-23 20:45:43 +0000134# The examples from PEP 255.
135
136pep_tests = """
137
Tim Peterse5614632001-08-15 04:41:19 +0000138Specification: Yield
139
140 Restriction: A generator cannot be resumed while it is actively
141 running:
142
143 >>> def g():
144 ... i = me.next()
145 ... yield i
146 >>> me = g()
147 >>> me.next()
148 Traceback (most recent call last):
149 ...
150 File "<string>", line 2, in g
151 ValueError: generator already executing
152
Tim Peters6ba5f792001-06-23 20:45:43 +0000153Specification: Return
154
155 Note that return isn't always equivalent to raising StopIteration: the
156 difference lies in how enclosing try/except constructs are treated.
157 For example,
158
159 >>> def f1():
160 ... try:
161 ... return
162 ... except:
163 ... yield 1
164 >>> print list(f1())
165 []
166
167 because, as in any function, return simply exits, but
168
169 >>> def f2():
170 ... try:
171 ... raise StopIteration
172 ... except:
173 ... yield 42
174 >>> print list(f2())
175 [42]
176
177 because StopIteration is captured by a bare "except", as is any
178 exception.
179
180Specification: Generators and Exception Propagation
181
182 >>> def f():
Tim Peters3caca232001-12-06 06:23:26 +0000183 ... return 1//0
Tim Peters6ba5f792001-06-23 20:45:43 +0000184 >>> def g():
185 ... yield f() # the zero division exception propagates
186 ... yield 42 # and we'll never get here
187 >>> k = g()
188 >>> k.next()
189 Traceback (most recent call last):
190 File "<stdin>", line 1, in ?
191 File "<stdin>", line 2, in g
192 File "<stdin>", line 2, in f
193 ZeroDivisionError: integer division or modulo by zero
194 >>> k.next() # and the generator cannot be resumed
195 Traceback (most recent call last):
196 File "<stdin>", line 1, in ?
197 StopIteration
198 >>>
199
200Specification: Try/Except/Finally
201
202 >>> def f():
203 ... try:
204 ... yield 1
205 ... try:
206 ... yield 2
Tim Peters3caca232001-12-06 06:23:26 +0000207 ... 1//0
Tim Peters6ba5f792001-06-23 20:45:43 +0000208 ... yield 3 # never get here
209 ... except ZeroDivisionError:
210 ... yield 4
211 ... yield 5
212 ... raise
213 ... except:
214 ... yield 6
215 ... yield 7 # the "raise" above stops this
216 ... except:
217 ... yield 8
218 ... yield 9
219 ... try:
220 ... x = 12
221 ... finally:
222 ... yield 10
223 ... yield 11
224 >>> print list(f())
225 [1, 2, 4, 5, 8, 9, 10, 11]
226 >>>
227
Tim Peters6ba5f792001-06-23 20:45:43 +0000228Guido's binary tree example.
229
230 >>> # A binary tree class.
231 >>> class Tree:
232 ...
233 ... def __init__(self, label, left=None, right=None):
234 ... self.label = label
235 ... self.left = left
236 ... self.right = right
237 ...
238 ... def __repr__(self, level=0, indent=" "):
Walter Dörwald70a6b492004-02-12 17:35:32 +0000239 ... s = level*indent + repr(self.label)
Tim Peters6ba5f792001-06-23 20:45:43 +0000240 ... if self.left:
241 ... s = s + "\\n" + self.left.__repr__(level+1, indent)
242 ... if self.right:
243 ... s = s + "\\n" + self.right.__repr__(level+1, indent)
244 ... return s
245 ...
246 ... def __iter__(self):
247 ... return inorder(self)
248
249 >>> # Create a Tree from a list.
250 >>> def tree(list):
251 ... n = len(list)
252 ... if n == 0:
253 ... return []
Tim Peters3caca232001-12-06 06:23:26 +0000254 ... i = n // 2
Tim Peters6ba5f792001-06-23 20:45:43 +0000255 ... return Tree(list[i], tree(list[:i]), tree(list[i+1:]))
256
257 >>> # Show it off: create a tree.
258 >>> t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
259
Tim Petersd674e172002-03-10 07:59:13 +0000260 >>> # A recursive generator that generates Tree labels in in-order.
Tim Peters6ba5f792001-06-23 20:45:43 +0000261 >>> def inorder(t):
262 ... if t:
263 ... for x in inorder(t.left):
264 ... yield x
265 ... yield t.label
266 ... for x in inorder(t.right):
267 ... yield x
268
269 >>> # Show it off: create a tree.
Edward Loper103d26e2004-08-09 02:03:30 +0000270 >>> t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
271 >>> # Print the nodes of the tree in in-order.
272 >>> for x in t:
Tim Peters6ba5f792001-06-23 20:45:43 +0000273 ... print x,
274 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
275
276 >>> # A non-recursive generator.
277 >>> def inorder(node):
278 ... stack = []
279 ... while node:
280 ... while node.left:
281 ... stack.append(node)
282 ... node = node.left
283 ... yield node.label
284 ... while not node.right:
285 ... try:
286 ... node = stack.pop()
287 ... except IndexError:
288 ... return
289 ... yield node.label
290 ... node = node.right
291
292 >>> # Exercise the non-recursive generator.
293 >>> for x in t:
294 ... print x,
295 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
296
297"""
298
Tim Petersb2bc6a92001-06-24 10:14:27 +0000299# Examples from Iterator-List and Python-Dev and c.l.py.
Tim Peters6ba5f792001-06-23 20:45:43 +0000300
301email_tests = """
302
303The difference between yielding None and returning it.
304
305>>> def g():
306... for i in range(3):
307... yield None
308... yield None
309... return
310>>> list(g())
311[None, None, None, None]
312
313Ensure that explicitly raising StopIteration acts like any other exception
314in try/except, not like a return.
315
316>>> def g():
317... yield 1
318... try:
319... raise StopIteration
320... except:
321... yield 2
322... yield 3
323>>> list(g())
324[1, 2, 3]
Tim Petersb9e9ff12001-06-24 03:44:52 +0000325
Tim Petersb2bc6a92001-06-24 10:14:27 +0000326Next one was posted to c.l.py.
327
328>>> def gcomb(x, k):
329... "Generate all combinations of k elements from list x."
330...
331... if k > len(x):
332... return
333... if k == 0:
334... yield []
335... else:
336... first, rest = x[0], x[1:]
337... # A combination does or doesn't contain first.
338... # If it does, the remainder is a k-1 comb of rest.
339... for c in gcomb(rest, k-1):
340... c.insert(0, first)
341... yield c
342... # If it doesn't contain first, it's a k comb of rest.
343... for c in gcomb(rest, k):
344... yield c
345
346>>> seq = range(1, 5)
347>>> for k in range(len(seq) + 2):
348... print "%d-combs of %s:" % (k, seq)
349... for c in gcomb(seq, k):
350... print " ", c
3510-combs of [1, 2, 3, 4]:
352 []
3531-combs of [1, 2, 3, 4]:
354 [1]
355 [2]
356 [3]
357 [4]
3582-combs of [1, 2, 3, 4]:
359 [1, 2]
360 [1, 3]
361 [1, 4]
362 [2, 3]
363 [2, 4]
364 [3, 4]
3653-combs of [1, 2, 3, 4]:
366 [1, 2, 3]
367 [1, 2, 4]
368 [1, 3, 4]
369 [2, 3, 4]
3704-combs of [1, 2, 3, 4]:
371 [1, 2, 3, 4]
3725-combs of [1, 2, 3, 4]:
Tim Peters3e7b1a02001-06-25 19:46:25 +0000373
Tim Peterse77f2e22001-06-26 22:24:51 +0000374From the Iterators list, about the types of these things.
Tim Peters3e7b1a02001-06-25 19:46:25 +0000375
376>>> def g():
377... yield 1
378...
379>>> type(g)
380<type 'function'>
381>>> i = g()
382>>> type(i)
383<type 'generator'>
Tim Peters5d2b77c2001-09-03 05:47:38 +0000384>>> [s for s in dir(i) if not s.startswith('_')]
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000385['close', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
Tim Peters3e7b1a02001-06-25 19:46:25 +0000386>>> print i.next.__doc__
Tim Peters6d6c1a32001-08-02 04:15:00 +0000387x.next() -> the next value, or raise StopIteration
Tim Peters3e7b1a02001-06-25 19:46:25 +0000388>>> iter(i) is i
Guido van Rossum77f6a652002-04-03 22:41:51 +0000389True
Tim Peters3e7b1a02001-06-25 19:46:25 +0000390>>> import types
391>>> isinstance(i, types.GeneratorType)
Guido van Rossum77f6a652002-04-03 22:41:51 +0000392True
Tim Peterse77f2e22001-06-26 22:24:51 +0000393
394And more, added later.
395
396>>> i.gi_running
3970
398>>> type(i.gi_frame)
399<type 'frame'>
400>>> i.gi_running = 42
401Traceback (most recent call last):
402 ...
Guido van Rossum61cf7802001-08-10 21:25:24 +0000403TypeError: readonly attribute
Tim Peterse77f2e22001-06-26 22:24:51 +0000404>>> def g():
405... yield me.gi_running
406>>> me = g()
407>>> me.gi_running
4080
409>>> me.next()
4101
411>>> me.gi_running
4120
Tim Peters35302662001-07-02 01:38:33 +0000413
414A clever union-find implementation from c.l.py, due to David Eppstein.
415Sent: Friday, June 29, 2001 12:16 PM
416To: python-list@python.org
417Subject: Re: PEP 255: Simple Generators
418
419>>> class disjointSet:
420... def __init__(self, name):
421... self.name = name
422... self.parent = None
423... self.generator = self.generate()
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000424... self.close = self.generator.close
Tim Peters35302662001-07-02 01:38:33 +0000425...
426... def generate(self):
427... while not self.parent:
428... yield self
429... for x in self.parent.generator:
430... yield x
431...
432... def find(self):
433... return self.generator.next()
434...
435... def union(self, parent):
436... if self.parent:
437... raise ValueError("Sorry, I'm not a root!")
438... self.parent = parent
439...
440... def __str__(self):
441... return self.name
Tim Peters35302662001-07-02 01:38:33 +0000442
443>>> names = "ABCDEFGHIJKLM"
444>>> sets = [disjointSet(name) for name in names]
445>>> roots = sets[:]
446
447>>> import random
Raymond Hettingerdd24a9f2002-12-30 00:46:09 +0000448>>> gen = random.WichmannHill(42)
Tim Peters35302662001-07-02 01:38:33 +0000449>>> while 1:
450... for s in sets:
451... print "%s->%s" % (s, s.find()),
452... print
453... if len(roots) > 1:
Raymond Hettingerdd24a9f2002-12-30 00:46:09 +0000454... s1 = gen.choice(roots)
Tim Peters35302662001-07-02 01:38:33 +0000455... roots.remove(s1)
Raymond Hettingerdd24a9f2002-12-30 00:46:09 +0000456... s2 = gen.choice(roots)
Tim Peters35302662001-07-02 01:38:33 +0000457... s1.union(s2)
458... print "merged", s1, "into", s2
459... else:
460... break
461A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->K L->L M->M
462merged D into G
463A->A B->B C->C D->G E->E F->F G->G H->H I->I J->J K->K L->L M->M
464merged C into F
465A->A B->B C->F D->G E->E F->F G->G H->H I->I J->J K->K L->L M->M
466merged L into A
467A->A B->B C->F D->G E->E F->F G->G H->H I->I J->J K->K L->A M->M
468merged H into E
469A->A B->B C->F D->G E->E F->F G->G H->E I->I J->J K->K L->A M->M
470merged B into E
471A->A B->E C->F D->G E->E F->F G->G H->E I->I J->J K->K L->A M->M
472merged J into G
473A->A B->E C->F D->G E->E F->F G->G H->E I->I J->G K->K L->A M->M
474merged E into G
475A->A B->G C->F D->G E->G F->F G->G H->G I->I J->G K->K L->A M->M
476merged M into G
477A->A B->G C->F D->G E->G F->F G->G H->G I->I J->G K->K L->A M->G
478merged I into K
479A->A B->G C->F D->G E->G F->F G->G H->G I->K J->G K->K L->A M->G
480merged K into A
481A->A B->G C->F D->G E->G F->F G->G H->G I->A J->G K->A L->A M->G
482merged F into A
483A->A B->G C->A D->G E->G F->A G->G H->G I->A J->G K->A L->A M->G
484merged A into G
485A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000486
Tim Peterse9fe7e02005-08-07 03:04:58 +0000487>>> for s in sets: s.close() # break cycles
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000488
Tim Peters6ba5f792001-06-23 20:45:43 +0000489"""
Barry Warsaw04f357c2002-07-23 19:04:11 +0000490# Emacs turd '
Tim Peters6ba5f792001-06-23 20:45:43 +0000491
Tim Peters0f9da0a2001-06-23 21:01:47 +0000492# Fun tests (for sufficiently warped notions of "fun").
493
494fun_tests = """
495
496Build up to a recursive Sieve of Eratosthenes generator.
497
498>>> def firstn(g, n):
499... return [g.next() for i in range(n)]
500
501>>> def intsfrom(i):
502... while 1:
503... yield i
504... i += 1
505
506>>> firstn(intsfrom(5), 7)
507[5, 6, 7, 8, 9, 10, 11]
508
509>>> def exclude_multiples(n, ints):
510... for i in ints:
511... if i % n:
512... yield i
513
514>>> firstn(exclude_multiples(3, intsfrom(1)), 6)
515[1, 2, 4, 5, 7, 8]
516
517>>> def sieve(ints):
518... prime = ints.next()
519... yield prime
520... not_divisible_by_prime = exclude_multiples(prime, ints)
521... for p in sieve(not_divisible_by_prime):
522... yield p
523
524>>> primes = sieve(intsfrom(2))
525>>> firstn(primes, 20)
526[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]
Tim Petersb9e9ff12001-06-24 03:44:52 +0000527
Tim Petersf6ed0742001-06-27 07:17:57 +0000528
Tim Petersb9e9ff12001-06-24 03:44:52 +0000529Another famous problem: generate all integers of the form
530 2**i * 3**j * 5**k
531in increasing order, where i,j,k >= 0. Trickier than it may look at first!
532Try writing it without generators, and correctly, and without generating
5333 internal results for each result output.
534
535>>> def times(n, g):
536... for i in g:
537... yield n * i
538>>> firstn(times(10, intsfrom(1)), 10)
539[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
540
541>>> def merge(g, h):
542... ng = g.next()
543... nh = h.next()
544... while 1:
545... if ng < nh:
546... yield ng
547... ng = g.next()
548... elif ng > nh:
549... yield nh
550... nh = h.next()
551... else:
552... yield ng
553... ng = g.next()
554... nh = h.next()
555
Tim Petersf6ed0742001-06-27 07:17:57 +0000556The following works, but is doing a whale of a lot of redundant work --
557it's not clear how to get the internal uses of m235 to share a single
558generator. Note that me_times2 (etc) each need to see every element in the
559result sequence. So this is an example where lazy lists are more natural
560(you can look at the head of a lazy list any number of times).
Tim Petersb9e9ff12001-06-24 03:44:52 +0000561
562>>> def m235():
563... yield 1
564... me_times2 = times(2, m235())
565... me_times3 = times(3, m235())
566... me_times5 = times(5, m235())
567... for i in merge(merge(me_times2,
568... me_times3),
569... me_times5):
570... yield i
571
Tim Petersf6ed0742001-06-27 07:17:57 +0000572Don't print "too many" of these -- the implementation above is extremely
573inefficient: each call of m235() leads to 3 recursive calls, and in
574turn each of those 3 more, and so on, and so on, until we've descended
575enough levels to satisfy the print stmts. Very odd: when I printed 5
576lines of results below, this managed to screw up Win98's malloc in "the
577usual" way, i.e. the heap grew over 4Mb so Win98 started fragmenting
578address space, and it *looked* like a very slow leak.
579
Tim Petersb9e9ff12001-06-24 03:44:52 +0000580>>> result = m235()
Tim Petersf6ed0742001-06-27 07:17:57 +0000581>>> for i in range(3):
Tim Petersb9e9ff12001-06-24 03:44:52 +0000582... print firstn(result, 15)
583[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
584[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
585[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
Tim Petersee309272001-06-24 05:47:06 +0000586
587Heh. Here's one way to get a shared list, complete with an excruciating
588namespace renaming trick. The *pretty* part is that the times() and merge()
589functions can be reused as-is, because they only assume their stream
590arguments are iterable -- a LazyList is the same as a generator to times().
591
592>>> class LazyList:
593... def __init__(self, g):
594... self.sofar = []
595... self.fetch = g.next
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000596... self.close = g.close
Tim Petersee309272001-06-24 05:47:06 +0000597...
598... def __getitem__(self, i):
599... sofar, fetch = self.sofar, self.fetch
600... while i >= len(sofar):
601... sofar.append(fetch())
602... return sofar[i]
603
604>>> def m235():
605... yield 1
Tim Petersea2e97a2001-06-24 07:10:02 +0000606... # Gack: m235 below actually refers to a LazyList.
Tim Petersee309272001-06-24 05:47:06 +0000607... me_times2 = times(2, m235)
608... me_times3 = times(3, m235)
609... me_times5 = times(5, m235)
610... for i in merge(merge(me_times2,
611... me_times3),
612... me_times5):
613... yield i
614
Tim Petersf6ed0742001-06-27 07:17:57 +0000615Print as many of these as you like -- *this* implementation is memory-
Neil Schemenauerb20e9db2001-07-12 13:26:41 +0000616efficient.
Tim Petersf6ed0742001-06-27 07:17:57 +0000617
Tim Petersee309272001-06-24 05:47:06 +0000618>>> m235 = LazyList(m235())
619>>> for i in range(5):
620... print [m235[j] for j in range(15*i, 15*(i+1))]
621[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
622[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
623[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
624[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
625[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Tim Petersf6ed0742001-06-27 07:17:57 +0000626
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000627>>> m235.close()
Tim Petersf6ed0742001-06-27 07:17:57 +0000628
629Ye olde Fibonacci generator, LazyList style.
630
631>>> def fibgen(a, b):
632...
633... def sum(g, h):
634... while 1:
635... yield g.next() + h.next()
636...
637... def tail(g):
638... g.next() # throw first away
639... for x in g:
640... yield x
641...
642... yield a
643... yield b
644... for s in sum(iter(fib),
645... tail(iter(fib))):
646... yield s
647
648>>> fib = LazyList(fibgen(1, 2))
649>>> firstn(iter(fib), 17)
650[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000651>>> fib.close()
Georg Brandl52715f62005-08-24 09:02:29 +0000652
653
654Running after your tail with itertools.tee (new in version 2.4)
655
656The algorithms "m235" (Hamming) and Fibonacci presented above are both
657examples of a whole family of FP (functional programming) algorithms
658where a function produces and returns a list while the production algorithm
659suppose the list as already produced by recursively calling itself.
660For these algorithms to work, they must:
661
662- produce at least a first element without presupposing the existence of
663 the rest of the list
664- produce their elements in a lazy manner
665
666To work efficiently, the beginning of the list must not be recomputed over
667and over again. This is ensured in most FP languages as a built-in feature.
668In python, we have to explicitly maintain a list of already computed results
669and abandon genuine recursivity.
670
671This is what had been attempted above with the LazyList class. One problem
672with that class is that it keeps a list of all of the generated results and
673therefore continually grows. This partially defeats the goal of the generator
674concept, viz. produce the results only as needed instead of producing them
675all and thereby wasting memory.
676
677Thanks to itertools.tee, it is now clear "how to get the internal uses of
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000678m235 to share a single generator". Unfortunately, using generators this way
679creates a reference-cycle that the garbage collector (currently) can't clean
680up, so we have to explicitly break the cycle (by calling the inner
681generator's close() method)
Georg Brandl52715f62005-08-24 09:02:29 +0000682
683>>> from itertools import tee
684>>> def m235():
685... def _m235():
686... yield 1
687... for n in merge(times(2, m2),
688... merge(times(3, m3),
689... times(5, m5))):
690... yield n
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000691... m1 = _m235()
692... m2, m3, m5, mRes = tee(m1, 4)
693... return m1.close, mRes
Georg Brandl52715f62005-08-24 09:02:29 +0000694
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000695>>> closer, it = m235()
Georg Brandl52715f62005-08-24 09:02:29 +0000696>>> for i in range(5):
697... print firstn(it, 15)
698[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
699[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
700[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
701[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
702[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000703>>> closer()
Georg Brandl52715f62005-08-24 09:02:29 +0000704
705The "tee" function does just what we want. It internally keeps a generated
706result for as long as it has not been "consumed" from all of the duplicated
707iterators, whereupon it is deleted. You can therefore print the hamming
708sequence during hours without increasing memory usage, or very little.
709
710The beauty of it is that recursive running after their tail FP algorithms
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000711are quite straightforwardly expressed with this Python idiom. The problem is
712that this creates the same kind of reference cycle as the m235()
713implementation above, and again we have to explicitly close the innermost
714generator to clean up the cycle.
Georg Brandl52715f62005-08-24 09:02:29 +0000715
716Ye olde Fibonacci generator, tee style.
717
718>>> def fib():
Tim Peters9e34c042005-08-26 15:20:46 +0000719...
Georg Brandl52715f62005-08-24 09:02:29 +0000720... def _isum(g, h):
721... while 1:
722... yield g.next() + h.next()
Tim Peters9e34c042005-08-26 15:20:46 +0000723...
Georg Brandl52715f62005-08-24 09:02:29 +0000724... def _fib():
725... yield 1
726... yield 2
727... fibTail.next() # throw first away
728... for res in _isum(fibHead, fibTail):
729... yield res
Tim Peters9e34c042005-08-26 15:20:46 +0000730...
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000731... realfib = _fib()
732... fibHead, fibTail, fibRes = tee(realfib, 3)
733... return realfib.close, fibRes
Georg Brandl52715f62005-08-24 09:02:29 +0000734
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000735>>> closer, fibber = fib()
736>>> firstn(fibber, 17)
Georg Brandl52715f62005-08-24 09:02:29 +0000737[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
Thomas Woutersa6126ba2006-03-31 15:31:43 +0000738>>> closer()
Georg Brandl52715f62005-08-24 09:02:29 +0000739
Tim Peters0f9da0a2001-06-23 21:01:47 +0000740"""
741
Tim Petersb6c3cea2001-06-26 03:36:28 +0000742# syntax_tests mostly provokes SyntaxErrors. Also fiddling with #if 0
743# hackery.
Tim Petersee309272001-06-24 05:47:06 +0000744
Tim Petersea2e97a2001-06-24 07:10:02 +0000745syntax_tests = """
746
Tim Petersaef8cfa2004-08-27 15:12:49 +0000747>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000748... return 22
749... yield 1
750Traceback (most recent call last):
Tim Peters77dcccc2004-08-27 05:44:51 +0000751 ..
Tim Petersc5684782004-09-13 01:07:12 +0000752SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[0]>, line 2)
Tim Petersea2e97a2001-06-24 07:10:02 +0000753
Tim Petersaef8cfa2004-08-27 15:12:49 +0000754>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000755... yield 1
756... return 22
757Traceback (most recent call last):
Tim Peters77dcccc2004-08-27 05:44:51 +0000758 ..
Tim Petersc5684782004-09-13 01:07:12 +0000759SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[1]>, line 3)
Tim Petersea2e97a2001-06-24 07:10:02 +0000760
761"return None" is not the same as "return" in a generator:
762
Tim Petersaef8cfa2004-08-27 15:12:49 +0000763>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000764... yield 1
765... return None
766Traceback (most recent call last):
Tim Peters77dcccc2004-08-27 05:44:51 +0000767 ..
Tim Petersc5684782004-09-13 01:07:12 +0000768SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[2]>, line 3)
Tim Petersea2e97a2001-06-24 07:10:02 +0000769
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000770These are fine:
Tim Petersea2e97a2001-06-24 07:10:02 +0000771
772>>> def f():
773... yield 1
774... return
775
Tim Petersaef8cfa2004-08-27 15:12:49 +0000776>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000777... try:
778... yield 1
779... finally:
780... pass
Tim Petersea2e97a2001-06-24 07:10:02 +0000781
Tim Petersaef8cfa2004-08-27 15:12:49 +0000782>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000783... try:
784... try:
Tim Peters3caca232001-12-06 06:23:26 +0000785... 1//0
Tim Petersea2e97a2001-06-24 07:10:02 +0000786... except ZeroDivisionError:
Tim Peters536cf992005-12-25 23:18:31 +0000787... yield 666
Tim Petersea2e97a2001-06-24 07:10:02 +0000788... except:
789... pass
790... finally:
791... pass
Tim Petersea2e97a2001-06-24 07:10:02 +0000792
793>>> def f():
794... try:
795... try:
796... yield 12
Tim Peters3caca232001-12-06 06:23:26 +0000797... 1//0
Tim Petersea2e97a2001-06-24 07:10:02 +0000798... except ZeroDivisionError:
799... yield 666
800... except:
801... try:
802... x = 12
803... finally:
804... yield 12
805... except:
806... return
807>>> list(f())
808[12, 666]
Tim Petersb6c3cea2001-06-26 03:36:28 +0000809
810>>> def f():
Tim Peters08a898f2001-06-28 01:52:22 +0000811... yield
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000812>>> type(f())
813<type 'generator'>
814
Tim Peters08a898f2001-06-28 01:52:22 +0000815
816>>> def f():
817... if 0:
818... yield
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000819>>> type(f())
820<type 'generator'>
821
Tim Peters08a898f2001-06-28 01:52:22 +0000822
823>>> def f():
Tim Petersb6c3cea2001-06-26 03:36:28 +0000824... if 0:
825... yield 1
826>>> type(f())
827<type 'generator'>
828
829>>> def f():
830... if "":
831... yield None
832>>> type(f())
833<type 'generator'>
834
835>>> def f():
836... return
837... try:
838... if x==4:
839... pass
840... elif 0:
841... try:
Tim Peters3caca232001-12-06 06:23:26 +0000842... 1//0
Tim Petersb6c3cea2001-06-26 03:36:28 +0000843... except SyntaxError:
844... pass
845... else:
846... if 0:
847... while 12:
848... x += 1
849... yield 2 # don't blink
850... f(a, b, c, d, e)
851... else:
852... pass
853... except:
854... x = 1
855... return
856>>> type(f())
857<type 'generator'>
858
859>>> def f():
860... if 0:
861... def g():
862... yield 1
863...
864>>> type(f())
Guido van Rossum297abad2001-08-16 08:32:39 +0000865<type 'NoneType'>
Tim Petersb6c3cea2001-06-26 03:36:28 +0000866
867>>> def f():
868... if 0:
869... class C:
870... def __init__(self):
871... yield 1
872... def f(self):
873... yield 2
874>>> type(f())
Guido van Rossum297abad2001-08-16 08:32:39 +0000875<type 'NoneType'>
Tim Peters08a898f2001-06-28 01:52:22 +0000876
877>>> def f():
878... if 0:
879... return
880... if 0:
881... yield 2
882>>> type(f())
883<type 'generator'>
884
885
Tim Petersaef8cfa2004-08-27 15:12:49 +0000886>>> def f():
Tim Peters08a898f2001-06-28 01:52:22 +0000887... if 0:
888... lambda x: x # shouldn't trigger here
889... return # or here
890... def f(i):
891... return 2*i # or here
892... if 0:
893... return 3 # but *this* sucks (line 8)
894... if 0:
895... yield 2 # because it's a generator
896Traceback (most recent call last):
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000897SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 8)
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +0000898
899This one caused a crash (see SF bug 567538):
900
901>>> def f():
902... for i in range(3):
903... try:
904... continue
905... finally:
906... yield i
Tim Petersc411dba2002-07-16 21:35:23 +0000907...
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +0000908>>> g = f()
909>>> print g.next()
9100
911>>> print g.next()
9121
913>>> print g.next()
9142
915>>> print g.next()
916Traceback (most recent call last):
917StopIteration
Tim Petersea2e97a2001-06-24 07:10:02 +0000918"""
919
Tim Petersbe4f0a72001-06-29 02:41:16 +0000920# conjoin is a simple backtracking generator, named in honor of Icon's
921# "conjunction" control structure. Pass a list of no-argument functions
922# that return iterable objects. Easiest to explain by example: assume the
923# function list [x, y, z] is passed. Then conjoin acts like:
924#
925# def g():
926# values = [None] * 3
927# for values[0] in x():
928# for values[1] in y():
929# for values[2] in z():
930# yield values
931#
932# So some 3-lists of values *may* be generated, each time we successfully
933# get into the innermost loop. If an iterator fails (is exhausted) before
934# then, it "backtracks" to get the next value from the nearest enclosing
935# iterator (the one "to the left"), and starts all over again at the next
936# slot (pumps a fresh iterator). Of course this is most useful when the
937# iterators have side-effects, so that which values *can* be generated at
938# each slot depend on the values iterated at previous slots.
939
940def conjoin(gs):
941
942 values = [None] * len(gs)
943
944 def gen(i, values=values):
945 if i >= len(gs):
946 yield values
947 else:
948 for values[i] in gs[i]():
949 for x in gen(i+1):
950 yield x
951
952 for x in gen(0):
953 yield x
954
Tim Petersc468fd22001-06-30 07:29:44 +0000955# That works fine, but recursing a level and checking i against len(gs) for
956# each item produced is inefficient. By doing manual loop unrolling across
957# generator boundaries, it's possible to eliminate most of that overhead.
958# This isn't worth the bother *in general* for generators, but conjoin() is
959# a core building block for some CPU-intensive generator applications.
960
961def conjoin(gs):
962
963 n = len(gs)
964 values = [None] * n
965
966 # Do one loop nest at time recursively, until the # of loop nests
967 # remaining is divisible by 3.
968
969 def gen(i, values=values):
970 if i >= n:
971 yield values
972
973 elif (n-i) % 3:
974 ip1 = i+1
975 for values[i] in gs[i]():
976 for x in gen(ip1):
977 yield x
978
979 else:
980 for x in _gen3(i):
981 yield x
982
983 # Do three loop nests at a time, recursing only if at least three more
984 # remain. Don't call directly: this is an internal optimization for
985 # gen's use.
986
987 def _gen3(i, values=values):
988 assert i < n and (n-i) % 3 == 0
989 ip1, ip2, ip3 = i+1, i+2, i+3
990 g, g1, g2 = gs[i : ip3]
991
992 if ip3 >= n:
993 # These are the last three, so we can yield values directly.
994 for values[i] in g():
995 for values[ip1] in g1():
996 for values[ip2] in g2():
997 yield values
998
999 else:
1000 # At least 6 loop nests remain; peel off 3 and recurse for the
1001 # rest.
1002 for values[i] in g():
1003 for values[ip1] in g1():
1004 for values[ip2] in g2():
1005 for x in _gen3(ip3):
1006 yield x
1007
1008 for x in gen(0):
1009 yield x
1010
unknown31569562001-07-04 22:11:22 +00001011# And one more approach: For backtracking apps like the Knight's Tour
1012# solver below, the number of backtracking levels can be enormous (one
1013# level per square, for the Knight's Tour, so that e.g. a 100x100 board
1014# needs 10,000 levels). In such cases Python is likely to run out of
1015# stack space due to recursion. So here's a recursion-free version of
1016# conjoin too.
1017# NOTE WELL: This allows large problems to be solved with only trivial
1018# demands on stack space. Without explicitly resumable generators, this is
Tim Peters9a8c8e22001-07-13 09:12:12 +00001019# much harder to achieve. OTOH, this is much slower (up to a factor of 2)
1020# than the fancy unrolled recursive conjoin.
unknown31569562001-07-04 22:11:22 +00001021
1022def flat_conjoin(gs): # rename to conjoin to run tests with this instead
1023 n = len(gs)
1024 values = [None] * n
1025 iters = [None] * n
Tim Peters9a8c8e22001-07-13 09:12:12 +00001026 _StopIteration = StopIteration # make local because caught a *lot*
unknown31569562001-07-04 22:11:22 +00001027 i = 0
Tim Peters9a8c8e22001-07-13 09:12:12 +00001028 while 1:
1029 # Descend.
1030 try:
1031 while i < n:
1032 it = iters[i] = gs[i]().next
1033 values[i] = it()
1034 i += 1
1035 except _StopIteration:
1036 pass
unknown31569562001-07-04 22:11:22 +00001037 else:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001038 assert i == n
1039 yield values
unknown31569562001-07-04 22:11:22 +00001040
Tim Peters9a8c8e22001-07-13 09:12:12 +00001041 # Backtrack until an older iterator can be resumed.
1042 i -= 1
unknown31569562001-07-04 22:11:22 +00001043 while i >= 0:
1044 try:
1045 values[i] = iters[i]()
Tim Peters9a8c8e22001-07-13 09:12:12 +00001046 # Success! Start fresh at next level.
unknown31569562001-07-04 22:11:22 +00001047 i += 1
1048 break
Tim Peters9a8c8e22001-07-13 09:12:12 +00001049 except _StopIteration:
1050 # Continue backtracking.
1051 i -= 1
1052 else:
1053 assert i < 0
1054 break
unknown31569562001-07-04 22:11:22 +00001055
Tim Petersbe4f0a72001-06-29 02:41:16 +00001056# A conjoin-based N-Queens solver.
1057
1058class Queens:
1059 def __init__(self, n):
1060 self.n = n
1061 rangen = range(n)
1062
1063 # Assign a unique int to each column and diagonal.
1064 # columns: n of those, range(n).
1065 # NW-SE diagonals: 2n-1 of these, i-j unique and invariant along
1066 # each, smallest i-j is 0-(n-1) = 1-n, so add n-1 to shift to 0-
1067 # based.
1068 # NE-SW diagonals: 2n-1 of these, i+j unique and invariant along
1069 # each, smallest i+j is 0, largest is 2n-2.
1070
1071 # For each square, compute a bit vector of the columns and
1072 # diagonals it covers, and for each row compute a function that
1073 # generates the possiblities for the columns in that row.
1074 self.rowgenerators = []
1075 for i in rangen:
1076 rowuses = [(1L << j) | # column ordinal
1077 (1L << (n + i-j + n-1)) | # NW-SE ordinal
1078 (1L << (n + 2*n-1 + i+j)) # NE-SW ordinal
1079 for j in rangen]
1080
1081 def rowgen(rowuses=rowuses):
1082 for j in rangen:
1083 uses = rowuses[j]
Tim Petersc468fd22001-06-30 07:29:44 +00001084 if uses & self.used == 0:
1085 self.used |= uses
1086 yield j
1087 self.used &= ~uses
Tim Petersbe4f0a72001-06-29 02:41:16 +00001088
1089 self.rowgenerators.append(rowgen)
1090
1091 # Generate solutions.
1092 def solve(self):
1093 self.used = 0
1094 for row2col in conjoin(self.rowgenerators):
1095 yield row2col
1096
1097 def printsolution(self, row2col):
1098 n = self.n
1099 assert n == len(row2col)
1100 sep = "+" + "-+" * n
1101 print sep
1102 for i in range(n):
1103 squares = [" " for j in range(n)]
1104 squares[row2col[i]] = "Q"
1105 print "|" + "|".join(squares) + "|"
1106 print sep
1107
unknown31569562001-07-04 22:11:22 +00001108# A conjoin-based Knight's Tour solver. This is pretty sophisticated
1109# (e.g., when used with flat_conjoin above, and passing hard=1 to the
1110# constructor, a 200x200 Knight's Tour was found quickly -- note that we're
Tim Peters9a8c8e22001-07-13 09:12:12 +00001111# creating 10s of thousands of generators then!), and is lengthy.
unknown31569562001-07-04 22:11:22 +00001112
1113class Knights:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001114 def __init__(self, m, n, hard=0):
1115 self.m, self.n = m, n
unknown31569562001-07-04 22:11:22 +00001116
Tim Peters9a8c8e22001-07-13 09:12:12 +00001117 # solve() will set up succs[i] to be a list of square #i's
1118 # successors.
1119 succs = self.succs = []
unknown31569562001-07-04 22:11:22 +00001120
Tim Peters9a8c8e22001-07-13 09:12:12 +00001121 # Remove i0 from each of its successor's successor lists, i.e.
1122 # successors can't go back to i0 again. Return 0 if we can
1123 # detect this makes a solution impossible, else return 1.
unknown31569562001-07-04 22:11:22 +00001124
Tim Peters9a8c8e22001-07-13 09:12:12 +00001125 def remove_from_successors(i0, len=len):
unknown31569562001-07-04 22:11:22 +00001126 # If we remove all exits from a free square, we're dead:
1127 # even if we move to it next, we can't leave it again.
1128 # If we create a square with one exit, we must visit it next;
1129 # else somebody else will have to visit it, and since there's
1130 # only one adjacent, there won't be a way to leave it again.
1131 # Finelly, if we create more than one free square with a
1132 # single exit, we can only move to one of them next, leaving
1133 # the other one a dead end.
1134 ne0 = ne1 = 0
1135 for i in succs[i0]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001136 s = succs[i]
1137 s.remove(i0)
1138 e = len(s)
1139 if e == 0:
1140 ne0 += 1
1141 elif e == 1:
1142 ne1 += 1
unknown31569562001-07-04 22:11:22 +00001143 return ne0 == 0 and ne1 < 2
1144
Tim Peters9a8c8e22001-07-13 09:12:12 +00001145 # Put i0 back in each of its successor's successor lists.
1146
1147 def add_to_successors(i0):
unknown31569562001-07-04 22:11:22 +00001148 for i in succs[i0]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001149 succs[i].append(i0)
unknown31569562001-07-04 22:11:22 +00001150
1151 # Generate the first move.
1152 def first():
Tim Peters9a8c8e22001-07-13 09:12:12 +00001153 if m < 1 or n < 1:
unknown31569562001-07-04 22:11:22 +00001154 return
1155
unknown31569562001-07-04 22:11:22 +00001156 # Since we're looking for a cycle, it doesn't matter where we
1157 # start. Starting in a corner makes the 2nd move easy.
Tim Peters9a8c8e22001-07-13 09:12:12 +00001158 corner = self.coords2index(0, 0)
1159 remove_from_successors(corner)
unknown31569562001-07-04 22:11:22 +00001160 self.lastij = corner
1161 yield corner
Tim Peters9a8c8e22001-07-13 09:12:12 +00001162 add_to_successors(corner)
unknown31569562001-07-04 22:11:22 +00001163
1164 # Generate the second moves.
1165 def second():
Tim Peters9a8c8e22001-07-13 09:12:12 +00001166 corner = self.coords2index(0, 0)
unknown31569562001-07-04 22:11:22 +00001167 assert self.lastij == corner # i.e., we started in the corner
Tim Peters9a8c8e22001-07-13 09:12:12 +00001168 if m < 3 or n < 3:
unknown31569562001-07-04 22:11:22 +00001169 return
Tim Peters9a8c8e22001-07-13 09:12:12 +00001170 assert len(succs[corner]) == 2
1171 assert self.coords2index(1, 2) in succs[corner]
1172 assert self.coords2index(2, 1) in succs[corner]
unknown31569562001-07-04 22:11:22 +00001173 # Only two choices. Whichever we pick, the other must be the
Tim Peters9a8c8e22001-07-13 09:12:12 +00001174 # square picked on move m*n, as it's the only way to get back
unknown31569562001-07-04 22:11:22 +00001175 # to (0, 0). Save its index in self.final so that moves before
1176 # the last know it must be kept free.
1177 for i, j in (1, 2), (2, 1):
Tim Peters9a8c8e22001-07-13 09:12:12 +00001178 this = self.coords2index(i, j)
1179 final = self.coords2index(3-i, 3-j)
unknown31569562001-07-04 22:11:22 +00001180 self.final = final
unknown31569562001-07-04 22:11:22 +00001181
Tim Peters9a8c8e22001-07-13 09:12:12 +00001182 remove_from_successors(this)
1183 succs[final].append(corner)
unknown31569562001-07-04 22:11:22 +00001184 self.lastij = this
1185 yield this
Tim Peters9a8c8e22001-07-13 09:12:12 +00001186 succs[final].remove(corner)
1187 add_to_successors(this)
unknown31569562001-07-04 22:11:22 +00001188
Tim Peters9a8c8e22001-07-13 09:12:12 +00001189 # Generate moves 3 thru m*n-1.
1190 def advance(len=len):
unknown31569562001-07-04 22:11:22 +00001191 # If some successor has only one exit, must take it.
1192 # Else favor successors with fewer exits.
1193 candidates = []
1194 for i in succs[self.lastij]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001195 e = len(succs[i])
1196 assert e > 0, "else remove_from_successors() pruning flawed"
1197 if e == 1:
1198 candidates = [(e, i)]
1199 break
1200 candidates.append((e, i))
unknown31569562001-07-04 22:11:22 +00001201 else:
1202 candidates.sort()
1203
1204 for e, i in candidates:
1205 if i != self.final:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001206 if remove_from_successors(i):
unknown31569562001-07-04 22:11:22 +00001207 self.lastij = i
1208 yield i
Tim Peters9a8c8e22001-07-13 09:12:12 +00001209 add_to_successors(i)
unknown31569562001-07-04 22:11:22 +00001210
Tim Peters9a8c8e22001-07-13 09:12:12 +00001211 # Generate moves 3 thru m*n-1. Alternative version using a
unknown31569562001-07-04 22:11:22 +00001212 # stronger (but more expensive) heuristic to order successors.
Tim Peters9a8c8e22001-07-13 09:12:12 +00001213 # Since the # of backtracking levels is m*n, a poor move early on
1214 # can take eons to undo. Smallest square board for which this
1215 # matters a lot is 52x52.
1216 def advance_hard(vmid=(m-1)/2.0, hmid=(n-1)/2.0, len=len):
unknown31569562001-07-04 22:11:22 +00001217 # If some successor has only one exit, must take it.
1218 # Else favor successors with fewer exits.
1219 # Break ties via max distance from board centerpoint (favor
1220 # corners and edges whenever possible).
1221 candidates = []
1222 for i in succs[self.lastij]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001223 e = len(succs[i])
1224 assert e > 0, "else remove_from_successors() pruning flawed"
1225 if e == 1:
1226 candidates = [(e, 0, i)]
1227 break
1228 i1, j1 = self.index2coords(i)
1229 d = (i1 - vmid)**2 + (j1 - hmid)**2
1230 candidates.append((e, -d, i))
unknown31569562001-07-04 22:11:22 +00001231 else:
1232 candidates.sort()
1233
1234 for e, d, i in candidates:
1235 if i != self.final:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001236 if remove_from_successors(i):
unknown31569562001-07-04 22:11:22 +00001237 self.lastij = i
1238 yield i
Tim Peters9a8c8e22001-07-13 09:12:12 +00001239 add_to_successors(i)
unknown31569562001-07-04 22:11:22 +00001240
1241 # Generate the last move.
1242 def last():
1243 assert self.final in succs[self.lastij]
1244 yield self.final
1245
Tim Peters9a8c8e22001-07-13 09:12:12 +00001246 if m*n < 4:
1247 self.squaregenerators = [first]
unknown31569562001-07-04 22:11:22 +00001248 else:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001249 self.squaregenerators = [first, second] + \
1250 [hard and advance_hard or advance] * (m*n - 3) + \
unknown31569562001-07-04 22:11:22 +00001251 [last]
1252
Tim Peters9a8c8e22001-07-13 09:12:12 +00001253 def coords2index(self, i, j):
1254 assert 0 <= i < self.m
1255 assert 0 <= j < self.n
1256 return i * self.n + j
1257
1258 def index2coords(self, index):
1259 assert 0 <= index < self.m * self.n
1260 return divmod(index, self.n)
1261
1262 def _init_board(self):
1263 succs = self.succs
1264 del succs[:]
1265 m, n = self.m, self.n
1266 c2i = self.coords2index
1267
1268 offsets = [( 1, 2), ( 2, 1), ( 2, -1), ( 1, -2),
1269 (-1, -2), (-2, -1), (-2, 1), (-1, 2)]
1270 rangen = range(n)
1271 for i in range(m):
1272 for j in rangen:
1273 s = [c2i(i+io, j+jo) for io, jo in offsets
1274 if 0 <= i+io < m and
1275 0 <= j+jo < n]
1276 succs.append(s)
1277
unknown31569562001-07-04 22:11:22 +00001278 # Generate solutions.
1279 def solve(self):
Tim Peters9a8c8e22001-07-13 09:12:12 +00001280 self._init_board()
1281 for x in conjoin(self.squaregenerators):
unknown31569562001-07-04 22:11:22 +00001282 yield x
1283
1284 def printsolution(self, x):
Tim Peters9a8c8e22001-07-13 09:12:12 +00001285 m, n = self.m, self.n
1286 assert len(x) == m*n
1287 w = len(str(m*n))
unknown31569562001-07-04 22:11:22 +00001288 format = "%" + str(w) + "d"
1289
Tim Peters9a8c8e22001-07-13 09:12:12 +00001290 squares = [[None] * n for i in range(m)]
unknown31569562001-07-04 22:11:22 +00001291 k = 1
1292 for i in x:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001293 i1, j1 = self.index2coords(i)
unknown31569562001-07-04 22:11:22 +00001294 squares[i1][j1] = format % k
1295 k += 1
1296
1297 sep = "+" + ("-" * w + "+") * n
1298 print sep
Tim Peters9a8c8e22001-07-13 09:12:12 +00001299 for i in range(m):
unknown31569562001-07-04 22:11:22 +00001300 row = squares[i]
1301 print "|" + "|".join(row) + "|"
1302 print sep
1303
Tim Petersbe4f0a72001-06-29 02:41:16 +00001304conjoin_tests = """
1305
1306Generate the 3-bit binary numbers in order. This illustrates dumbest-
1307possible use of conjoin, just to generate the full cross-product.
1308
unknown31569562001-07-04 22:11:22 +00001309>>> for c in conjoin([lambda: iter((0, 1))] * 3):
Tim Petersbe4f0a72001-06-29 02:41:16 +00001310... print c
1311[0, 0, 0]
1312[0, 0, 1]
1313[0, 1, 0]
1314[0, 1, 1]
1315[1, 0, 0]
1316[1, 0, 1]
1317[1, 1, 0]
1318[1, 1, 1]
1319
Tim Petersc468fd22001-06-30 07:29:44 +00001320For efficiency in typical backtracking apps, conjoin() yields the same list
1321object each time. So if you want to save away a full account of its
1322generated sequence, you need to copy its results.
1323
1324>>> def gencopy(iterator):
1325... for x in iterator:
1326... yield x[:]
1327
1328>>> for n in range(10):
unknown31569562001-07-04 22:11:22 +00001329... all = list(gencopy(conjoin([lambda: iter((0, 1))] * n)))
Tim Petersc468fd22001-06-30 07:29:44 +00001330... print n, len(all), all[0] == [0] * n, all[-1] == [1] * n
Guido van Rossum77f6a652002-04-03 22:41:51 +000013310 1 True True
13321 2 True True
13332 4 True True
13343 8 True True
13354 16 True True
13365 32 True True
13376 64 True True
13387 128 True True
13398 256 True True
13409 512 True True
Tim Petersc468fd22001-06-30 07:29:44 +00001341
Tim Petersbe4f0a72001-06-29 02:41:16 +00001342And run an 8-queens solver.
1343
1344>>> q = Queens(8)
1345>>> LIMIT = 2
1346>>> count = 0
1347>>> for row2col in q.solve():
1348... count += 1
1349... if count <= LIMIT:
1350... print "Solution", count
1351... q.printsolution(row2col)
1352Solution 1
1353+-+-+-+-+-+-+-+-+
1354|Q| | | | | | | |
1355+-+-+-+-+-+-+-+-+
1356| | | | |Q| | | |
1357+-+-+-+-+-+-+-+-+
1358| | | | | | | |Q|
1359+-+-+-+-+-+-+-+-+
1360| | | | | |Q| | |
1361+-+-+-+-+-+-+-+-+
1362| | |Q| | | | | |
1363+-+-+-+-+-+-+-+-+
1364| | | | | | |Q| |
1365+-+-+-+-+-+-+-+-+
1366| |Q| | | | | | |
1367+-+-+-+-+-+-+-+-+
1368| | | |Q| | | | |
1369+-+-+-+-+-+-+-+-+
1370Solution 2
1371+-+-+-+-+-+-+-+-+
1372|Q| | | | | | | |
1373+-+-+-+-+-+-+-+-+
1374| | | | | |Q| | |
1375+-+-+-+-+-+-+-+-+
1376| | | | | | | |Q|
1377+-+-+-+-+-+-+-+-+
1378| | |Q| | | | | |
1379+-+-+-+-+-+-+-+-+
1380| | | | | | |Q| |
1381+-+-+-+-+-+-+-+-+
1382| | | |Q| | | | |
1383+-+-+-+-+-+-+-+-+
1384| |Q| | | | | | |
1385+-+-+-+-+-+-+-+-+
1386| | | | |Q| | | |
1387+-+-+-+-+-+-+-+-+
1388
1389>>> print count, "solutions in all."
139092 solutions in all.
unknown31569562001-07-04 22:11:22 +00001391
1392And run a Knight's Tour on a 10x10 board. Note that there are about
139320,000 solutions even on a 6x6 board, so don't dare run this to exhaustion.
1394
Tim Peters9a8c8e22001-07-13 09:12:12 +00001395>>> k = Knights(10, 10)
unknown31569562001-07-04 22:11:22 +00001396>>> LIMIT = 2
1397>>> count = 0
1398>>> for x in k.solve():
1399... count += 1
1400... if count <= LIMIT:
1401... print "Solution", count
1402... k.printsolution(x)
1403... else:
1404... break
1405Solution 1
1406+---+---+---+---+---+---+---+---+---+---+
1407| 1| 58| 27| 34| 3| 40| 29| 10| 5| 8|
1408+---+---+---+---+---+---+---+---+---+---+
1409| 26| 35| 2| 57| 28| 33| 4| 7| 30| 11|
1410+---+---+---+---+---+---+---+---+---+---+
1411| 59|100| 73| 36| 41| 56| 39| 32| 9| 6|
1412+---+---+---+---+---+---+---+---+---+---+
1413| 74| 25| 60| 55| 72| 37| 42| 49| 12| 31|
1414+---+---+---+---+---+---+---+---+---+---+
1415| 61| 86| 99| 76| 63| 52| 47| 38| 43| 50|
1416+---+---+---+---+---+---+---+---+---+---+
1417| 24| 75| 62| 85| 54| 71| 64| 51| 48| 13|
1418+---+---+---+---+---+---+---+---+---+---+
1419| 87| 98| 91| 80| 77| 84| 53| 46| 65| 44|
1420+---+---+---+---+---+---+---+---+---+---+
1421| 90| 23| 88| 95| 70| 79| 68| 83| 14| 17|
1422+---+---+---+---+---+---+---+---+---+---+
1423| 97| 92| 21| 78| 81| 94| 19| 16| 45| 66|
1424+---+---+---+---+---+---+---+---+---+---+
1425| 22| 89| 96| 93| 20| 69| 82| 67| 18| 15|
1426+---+---+---+---+---+---+---+---+---+---+
1427Solution 2
1428+---+---+---+---+---+---+---+---+---+---+
1429| 1| 58| 27| 34| 3| 40| 29| 10| 5| 8|
1430+---+---+---+---+---+---+---+---+---+---+
1431| 26| 35| 2| 57| 28| 33| 4| 7| 30| 11|
1432+---+---+---+---+---+---+---+---+---+---+
1433| 59|100| 73| 36| 41| 56| 39| 32| 9| 6|
1434+---+---+---+---+---+---+---+---+---+---+
1435| 74| 25| 60| 55| 72| 37| 42| 49| 12| 31|
1436+---+---+---+---+---+---+---+---+---+---+
1437| 61| 86| 99| 76| 63| 52| 47| 38| 43| 50|
1438+---+---+---+---+---+---+---+---+---+---+
1439| 24| 75| 62| 85| 54| 71| 64| 51| 48| 13|
1440+---+---+---+---+---+---+---+---+---+---+
1441| 87| 98| 89| 80| 77| 84| 53| 46| 65| 44|
1442+---+---+---+---+---+---+---+---+---+---+
1443| 90| 23| 92| 95| 70| 79| 68| 83| 14| 17|
1444+---+---+---+---+---+---+---+---+---+---+
1445| 97| 88| 21| 78| 81| 94| 19| 16| 45| 66|
1446+---+---+---+---+---+---+---+---+---+---+
1447| 22| 91| 96| 93| 20| 69| 82| 67| 18| 15|
1448+---+---+---+---+---+---+---+---+---+---+
Tim Petersbe4f0a72001-06-29 02:41:16 +00001449"""
1450
Fred Drake56d12662002-08-09 18:37:10 +00001451weakref_tests = """\
1452Generators are weakly referencable:
1453
1454>>> import weakref
1455>>> def gen():
1456... yield 'foo!'
1457...
1458>>> wr = weakref.ref(gen)
1459>>> wr() is gen
1460True
1461>>> p = weakref.proxy(gen)
1462
1463Generator-iterators are weakly referencable as well:
1464
1465>>> gi = gen()
1466>>> wr = weakref.ref(gi)
1467>>> wr() is gi
1468True
1469>>> p = weakref.proxy(gi)
1470>>> list(p)
1471['foo!']
1472
1473"""
1474
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001475coroutine_tests = """\
1476Sending a value into a started generator:
1477
1478>>> def f():
1479... print (yield 1)
1480... yield 2
1481>>> g = f()
1482>>> g.next()
14831
1484>>> g.send(42)
148542
14862
1487
1488Sending a value into a new generator produces a TypeError:
1489
1490>>> f().send("foo")
1491Traceback (most recent call last):
1492...
1493TypeError: can't send non-None value to a just-started generator
1494
1495
1496Yield by itself yields None:
1497
1498>>> def f(): yield
1499>>> list(f())
1500[None]
1501
1502
1503
1504An obscene abuse of a yield expression within a generator expression:
1505
1506>>> list((yield 21) for i in range(4))
1507[21, None, 21, None, 21, None, 21, None]
1508
1509And a more sane, but still weird usage:
1510
1511>>> def f(): list(i for i in [(yield 26)])
1512>>> type(f())
1513<type 'generator'>
1514
1515
1516Check some syntax errors for yield expressions:
1517
1518>>> f=lambda: (yield 1),(yield 2)
1519Traceback (most recent call last):
1520 ...
1521SyntaxError: 'yield' outside function (<doctest test.test_generators.__test__.coroutine[10]>, line 1)
1522
1523>>> def f(): return lambda x=(yield): 1
1524Traceback (most recent call last):
1525 ...
1526SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.coroutine[11]>, line 1)
1527
1528>>> def f(): x = yield = y
1529Traceback (most recent call last):
1530 ...
1531SyntaxError: assignment to yield expression not possible (<doctest test.test_generators.__test__.coroutine[12]>, line 1)
1532
1533
1534Now check some throw() conditions:
1535
1536>>> def f():
1537... while True:
1538... try:
1539... print (yield)
1540... except ValueError,v:
1541... print "caught ValueError (%s)" % (v),
1542>>> import sys
1543>>> g = f()
1544>>> g.next()
1545
1546>>> g.throw(ValueError) # type only
1547caught ValueError ()
1548
1549>>> g.throw(ValueError("xyz")) # value only
1550caught ValueError (xyz)
1551
1552>>> g.throw(ValueError, ValueError(1)) # value+matching type
1553caught ValueError (1)
1554
1555>>> g.throw(ValueError, TypeError(1)) # mismatched type, rewrapped
1556caught ValueError (1)
1557
Phillip J. Ebybee07122006-03-25 00:05:50 +00001558>>> g.throw(ValueError, ValueError(1), None) # explicit None traceback
1559caught ValueError (1)
1560
Tim Peterse9fe7e02005-08-07 03:04:58 +00001561>>> g.throw(ValueError(1), "foo") # bad args
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001562Traceback (most recent call last):
1563 ...
1564TypeError: instance exception may not have a separate value
1565
Tim Peterse9fe7e02005-08-07 03:04:58 +00001566>>> g.throw(ValueError, "foo", 23) # bad args
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001567Traceback (most recent call last):
1568 ...
1569TypeError: throw() third argument must be a traceback object
1570
1571>>> def throw(g,exc):
1572... try:
1573... raise exc
1574... except:
1575... g.throw(*sys.exc_info())
Tim Peterse9fe7e02005-08-07 03:04:58 +00001576>>> throw(g,ValueError) # do it with traceback included
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001577caught ValueError ()
1578
1579>>> g.send(1)
15801
1581
Tim Peterse9fe7e02005-08-07 03:04:58 +00001582>>> throw(g,TypeError) # terminate the generator
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001583Traceback (most recent call last):
1584 ...
1585TypeError
1586
1587>>> print g.gi_frame
1588None
1589
1590>>> g.send(2)
1591Traceback (most recent call last):
1592 ...
1593StopIteration
1594
Tim Peterse9fe7e02005-08-07 03:04:58 +00001595>>> g.throw(ValueError,6) # throw on closed generator
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001596Traceback (most recent call last):
1597 ...
1598ValueError: 6
1599
Tim Peterse9fe7e02005-08-07 03:04:58 +00001600>>> f().throw(ValueError,7) # throw on just-opened generator
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001601Traceback (most recent call last):
1602 ...
1603ValueError: 7
1604
Neal Norwitzfcf44352005-11-27 20:37:43 +00001605>>> f().throw("abc") # throw on just-opened generator
1606Traceback (most recent call last):
1607 ...
Phillip J. Ebybee07122006-03-25 00:05:50 +00001608abc
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001609
1610Now let's try closing a generator:
1611
1612>>> def f():
1613... try: yield
1614... except GeneratorExit:
1615... print "exiting"
1616
1617>>> g = f()
1618>>> g.next()
1619>>> g.close()
1620exiting
1621>>> g.close() # should be no-op now
1622
1623>>> f().close() # close on just-opened generator should be fine
1624
Tim Peterse9fe7e02005-08-07 03:04:58 +00001625>>> def f(): yield # an even simpler generator
1626>>> f().close() # close before opening
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001627>>> g = f()
1628>>> g.next()
Tim Peterse9fe7e02005-08-07 03:04:58 +00001629>>> g.close() # close normally
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001630
1631And finalization:
1632
1633>>> def f():
1634... try: yield
1635... finally:
1636... print "exiting"
1637
1638>>> g = f()
1639>>> g.next()
1640>>> del g
1641exiting
1642
1643
1644Now let's try some ill-behaved generators:
1645
1646>>> def f():
1647... try: yield
1648... except GeneratorExit:
1649... yield "foo!"
1650>>> g = f()
1651>>> g.next()
1652>>> g.close()
1653Traceback (most recent call last):
1654 ...
1655RuntimeError: generator ignored GeneratorExit
1656>>> g.close()
1657
1658
1659Our ill-behaved code should be invoked during GC:
1660
1661>>> import sys, StringIO
1662>>> old, sys.stderr = sys.stderr, StringIO.StringIO()
1663>>> g = f()
1664>>> g.next()
1665>>> del g
1666>>> sys.stderr.getvalue().startswith(
1667... "Exception exceptions.RuntimeError: 'generator ignored GeneratorExit' in "
1668... )
1669True
1670>>> sys.stderr = old
1671
1672
1673And errors thrown during closing should propagate:
1674
1675>>> def f():
1676... try: yield
1677... except GeneratorExit:
1678... raise TypeError("fie!")
1679>>> g = f()
1680>>> g.next()
1681>>> g.close()
1682Traceback (most recent call last):
1683 ...
1684TypeError: fie!
1685
1686
1687Ensure that various yield expression constructs make their
1688enclosing function a generator:
1689
1690>>> def f(): x += yield
1691>>> type(f())
1692<type 'generator'>
1693
1694>>> def f(): x = yield
1695>>> type(f())
1696<type 'generator'>
1697
1698>>> def f(): lambda x=(yield): 1
1699>>> type(f())
1700<type 'generator'>
1701
1702>>> def f(): x=(i for i in (yield) if (yield))
1703>>> type(f())
1704<type 'generator'>
1705
1706>>> def f(d): d[(yield "a")] = d[(yield "b")] = 27
1707>>> data = [1,2]
1708>>> g = f(data)
1709>>> type(g)
1710<type 'generator'>
1711>>> g.send(None)
1712'a'
1713>>> data
1714[1, 2]
1715>>> g.send(0)
1716'b'
1717>>> data
1718[27, 2]
1719>>> try: g.send(1)
1720... except StopIteration: pass
1721>>> data
1722[27, 27]
1723
1724"""
1725
Thomas Wouters4054b972006-03-28 08:44:55 +00001726refleaks_tests = """
1727Prior to adding cycle-GC support to itertools.tee, this code would leak
1728references. We add it to the standard suite so the routine refleak-tests
1729would trigger if it starts being uncleanable again.
1730
1731>>> import itertools
1732>>> def leak():
1733... class gen:
1734... def __iter__(self):
1735... return self
1736... def next(self):
1737... return self.item
1738... g = gen()
1739... head, tail = itertools.tee(g)
1740... g.item = head
1741... return head
1742>>> it = leak()
1743
1744Make sure to also test the involvement of the tee-internal teedataobject,
1745which stores returned items.
1746
1747>>> item = it.next()
1748
1749There should be more test_generator-induced refleaks here, after they get
1750fixed.
1751
1752"""
1753
Tim Petersf6ed0742001-06-27 07:17:57 +00001754__test__ = {"tut": tutorial_tests,
1755 "pep": pep_tests,
1756 "email": email_tests,
1757 "fun": fun_tests,
Tim Petersbe4f0a72001-06-29 02:41:16 +00001758 "syntax": syntax_tests,
Fred Drake56d12662002-08-09 18:37:10 +00001759 "conjoin": conjoin_tests,
1760 "weakref": weakref_tests,
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001761 "coroutine": coroutine_tests,
Thomas Wouters4054b972006-03-28 08:44:55 +00001762 "refleaks": refleaks_tests,
Fred Drake56d12662002-08-09 18:37:10 +00001763 }
Tim Peters1def3512001-06-23 20:27:04 +00001764
1765# Magic test name that regrtest.py invokes *after* importing this module.
1766# This worms around a bootstrap problem.
1767# Note that doctest and regrtest both look in sys.argv for a "-v" argument,
1768# so this works as expected in both ways of running regrtest.
Tim Petersa0a62222001-09-09 06:12:01 +00001769def test_main(verbose=None):
Barry Warsaw04f357c2002-07-23 19:04:11 +00001770 from test import test_support, test_generators
Tim Peterscca01832004-08-27 15:29:59 +00001771 test_support.run_doctest(test_generators, verbose)
Tim Peters1def3512001-06-23 20:27:04 +00001772
1773# This part isn't needed for regrtest, but for running the test directly.
1774if __name__ == "__main__":
Tim Petersa0a62222001-09-09 06:12:01 +00001775 test_main(1)