blob: 958054aef5228a644de12ea72d7ff35e85b71b4d [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():
Guido van Rossum7131f842007-02-09 20:13:25 +00009 ... print(i)
Tim Petersb9e9ff12001-06-24 03:44:52 +000010 1
11 2
Tim Peters1def3512001-06-23 20:27:04 +000012 >>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +000013 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000014 1
Georg Brandla18af4e2007-04-21 15:47:16 +000015 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000016 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
Georg Brandla18af4e2007-04-21 15:47:16 +000020 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000021 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()
Georg Brandla18af4e2007-04-21 15:47:16 +000034 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000035 1
Georg Brandla18af4e2007-04-21 15:47:16 +000036 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000037 Traceback (most recent call last):
38 File "<stdin>", line 1, in ?
39 File "<stdin>", line 3, in f
40 StopIteration
Georg Brandla18af4e2007-04-21 15:47:16 +000041 >>> next(g) # once stopped, can't be resumed
Tim Peters1def3512001-06-23 20:27:04 +000042 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()
Georg Brandla18af4e2007-04-21 15:47:16 +000054 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000055 1
Georg Brandla18af4e2007-04-21 15:47:16 +000056 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000057 Traceback (most recent call last):
58 File "<stdin>", line 1, in ?
59 StopIteration
Georg Brandla18af4e2007-04-21 15:47:16 +000060 >>> next(g)
Tim Peters1def3512001-06-23 20:27:04 +000061 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
Guido van Rossum7131f842007-02-09 20:13:25 +000081 >>> print(list(g2()))
Tim Peters1def3512001-06-23 20:27:04 +000082 [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)
Georg Brandla18af4e2007-04-21 15:47:16 +0000108 ... print("creator", next(r))
Tim Peters1def3512001-06-23 20:27:04 +0000109 ... return r
Guido van Rossumc420b2f2007-02-09 22:09:01 +0000110 ...
Tim Peters1def3512001-06-23 20:27:04 +0000111 >>> def caller():
112 ... r = creator()
113 ... for i in r:
Guido van Rossum7131f842007-02-09 20:13:25 +0000114 ... print("caller", i)
Guido van Rossumc420b2f2007-02-09 22:09:01 +0000115 ...
Tim Peters1def3512001-06-23 20:27:04 +0000116 >>> 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():
Georg Brandla18af4e2007-04-21 15:47:16 +0000144 ... i = next(me)
Tim Peterse5614632001-08-15 04:41:19 +0000145 ... yield i
146 >>> me = g()
Georg Brandla18af4e2007-04-21 15:47:16 +0000147 >>> next(me)
Tim Peterse5614632001-08-15 04:41:19 +0000148 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
Guido van Rossum7131f842007-02-09 20:13:25 +0000164 >>> print(list(f1()))
Tim Peters6ba5f792001-06-23 20:45:43 +0000165 []
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
Guido van Rossum7131f842007-02-09 20:13:25 +0000174 >>> print(list(f2()))
Tim Peters6ba5f792001-06-23 20:45:43 +0000175 [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()
Georg Brandla18af4e2007-04-21 15:47:16 +0000188 >>> next(k)
Tim Peters6ba5f792001-06-23 20:45:43 +0000189 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
Georg Brandla18af4e2007-04-21 15:47:16 +0000194 >>> next(k) # and the generator cannot be resumed
Tim Peters6ba5f792001-06-23 20:45:43 +0000195 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
Guido van Rossum7131f842007-02-09 20:13:25 +0000224 >>> print(list(f()))
Tim Peters6ba5f792001-06-23 20:45:43 +0000225 [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:
Guido van Rossumc420b2f2007-02-09 22:09:01 +0000273 ... print(' '+x, end='')
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
Tim Peters6ba5f792001-06-23 20:45:43 +0000275
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:
Guido van Rossumc420b2f2007-02-09 22:09:01 +0000294 ... print(' '+x, end='')
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
Tim Peters6ba5f792001-06-23 20:45:43 +0000296
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
Guido van Rossum805365e2007-05-07 22:24:25 +0000346>>> seq = list(range(1, 5))
Tim Petersb2bc6a92001-06-24 10:14:27 +0000347>>> for k in range(len(seq) + 2):
Guido van Rossum7131f842007-02-09 20:13:25 +0000348... print("%d-combs of %s:" % (k, seq))
Tim Petersb2bc6a92001-06-24 10:14:27 +0000349... for c in gcomb(seq, k):
Guido van Rossum7131f842007-02-09 20:13:25 +0000350... print(" ", c)
Tim Petersb2bc6a92001-06-24 10:14:27 +00003510-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)
Martin v. Löwis250ad612008-04-07 05:43:42 +0000380<class 'function'>
Tim Peters3e7b1a02001-06-25 19:46:25 +0000381>>> i = g()
382>>> type(i)
Martin v. Löwis250ad612008-04-07 05:43:42 +0000383<class 'generator'>
Tim Peters5d2b77c2001-09-03 05:47:38 +0000384>>> [s for s in dir(i) if not s.startswith('_')]
Christian Heimesaf98da12008-01-27 15:18:18 +0000385['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw']
Serhiy Storchaka9a11f172013-01-31 16:11:04 +0200386>>> from test.support import HAVE_DOCSTRINGS
387>>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'x.__next__() <==> next(x)')
Georg Brandla18af4e2007-04-21 15:47:16 +0000388x.__next__() <==> next(x)
Tim Peters3e7b1a02001-06-25 19:46:25 +0000389>>> iter(i) is i
Guido van Rossum77f6a652002-04-03 22:41:51 +0000390True
Tim Peters3e7b1a02001-06-25 19:46:25 +0000391>>> import types
392>>> isinstance(i, types.GeneratorType)
Guido van Rossum77f6a652002-04-03 22:41:51 +0000393True
Tim Peterse77f2e22001-06-26 22:24:51 +0000394
395And more, added later.
396
397>>> i.gi_running
3980
399>>> type(i.gi_frame)
Martin v. Löwis250ad612008-04-07 05:43:42 +0000400<class 'frame'>
Tim Peterse77f2e22001-06-26 22:24:51 +0000401>>> i.gi_running = 42
402Traceback (most recent call last):
403 ...
Collin Winter42dae6a2007-03-28 21:44:53 +0000404AttributeError: readonly attribute
Tim Peterse77f2e22001-06-26 22:24:51 +0000405>>> def g():
406... yield me.gi_running
407>>> me = g()
408>>> me.gi_running
4090
Georg Brandla18af4e2007-04-21 15:47:16 +0000410>>> next(me)
Tim Peterse77f2e22001-06-26 22:24:51 +00004111
412>>> me.gi_running
4130
Tim Peters35302662001-07-02 01:38:33 +0000414
415A clever union-find implementation from c.l.py, due to David Eppstein.
416Sent: Friday, June 29, 2001 12:16 PM
417To: python-list@python.org
418Subject: Re: PEP 255: Simple Generators
419
420>>> class disjointSet:
421... def __init__(self, name):
422... self.name = name
423... self.parent = None
424... self.generator = self.generate()
425...
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):
Georg Brandla18af4e2007-04-21 15:47:16 +0000433... return next(self.generator)
Tim Peters35302662001-07-02 01:38:33 +0000434...
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 Hettinger28de64f2008-01-13 23:40:30 +0000448>>> gen = random.Random(42)
Tim Peters35302662001-07-02 01:38:33 +0000449>>> while 1:
450... for s in sets:
Guido van Rossumc420b2f2007-02-09 22:09:01 +0000451... print(" %s->%s" % (s, s.find()), end='')
Guido van Rossum7131f842007-02-09 20:13:25 +0000452... print()
Tim Peters35302662001-07-02 01:38:33 +0000453... 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)
Guido van Rossum7131f842007-02-09 20:13:25 +0000458... print("merged", s1, "into", s2)
Tim Peters35302662001-07-02 01:38:33 +0000459... else:
460... break
Guido van Rossumc420b2f2007-02-09 22:09:01 +0000461 A->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
Raymond Hettingerc585eec2010-09-07 15:00:15 +0000462merged K into B
463 A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->B L->L M->M
Raymond Hettinger28de64f2008-01-13 23:40:30 +0000464merged A into F
Raymond Hettingerc585eec2010-09-07 15:00:15 +0000465 A->F B->B C->C D->D E->E F->F G->G H->H I->I J->J K->B L->L M->M
466merged E into F
467 A->F B->B C->C D->D E->F F->F G->G H->H I->I J->J K->B L->L M->M
468merged D into C
469 A->F B->B C->C D->C E->F F->F G->G H->H I->I J->J K->B L->L M->M
Raymond Hettinger28de64f2008-01-13 23:40:30 +0000470merged M into C
Raymond Hettingerc585eec2010-09-07 15:00:15 +0000471 A->F B->B C->C D->C E->F F->F G->G H->H I->I J->J K->B L->L M->C
472merged J into B
473 A->F B->B C->C D->C E->F F->F G->G H->H I->I J->B K->B L->L M->C
474merged B into C
475 A->F B->C C->C D->C E->F F->F G->G H->H I->I J->C K->C L->L M->C
476merged F into G
477 A->G B->C C->C D->C E->G F->G G->G H->H I->I J->C K->C L->L M->C
478merged L into C
479 A->G B->C C->C D->C E->G F->G G->G H->H I->I J->C K->C L->C M->C
480merged G into I
481 A->I B->C C->C D->C E->I F->I G->I H->H I->I J->C K->C L->C M->C
482merged I into H
483 A->H B->C C->C D->C E->H F->H G->H H->H I->H J->C K->C L->C M->C
484merged C into H
485 A->H B->H C->H D->H E->H F->H G->H H->H I->H J->H K->H L->H M->H
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000486
Tim Peters6ba5f792001-06-23 20:45:43 +0000487"""
Barry Warsaw04f357c2002-07-23 19:04:11 +0000488# Emacs turd '
Tim Peters6ba5f792001-06-23 20:45:43 +0000489
Tim Peters0f9da0a2001-06-23 21:01:47 +0000490# Fun tests (for sufficiently warped notions of "fun").
491
492fun_tests = """
493
494Build up to a recursive Sieve of Eratosthenes generator.
495
496>>> def firstn(g, n):
Georg Brandla18af4e2007-04-21 15:47:16 +0000497... return [next(g) for i in range(n)]
Tim Peters0f9da0a2001-06-23 21:01:47 +0000498
499>>> def intsfrom(i):
500... while 1:
501... yield i
502... i += 1
503
504>>> firstn(intsfrom(5), 7)
505[5, 6, 7, 8, 9, 10, 11]
506
507>>> def exclude_multiples(n, ints):
508... for i in ints:
509... if i % n:
510... yield i
511
512>>> firstn(exclude_multiples(3, intsfrom(1)), 6)
513[1, 2, 4, 5, 7, 8]
514
515>>> def sieve(ints):
Georg Brandla18af4e2007-04-21 15:47:16 +0000516... prime = next(ints)
Tim Peters0f9da0a2001-06-23 21:01:47 +0000517... yield prime
518... not_divisible_by_prime = exclude_multiples(prime, ints)
519... for p in sieve(not_divisible_by_prime):
520... yield p
521
522>>> primes = sieve(intsfrom(2))
523>>> firstn(primes, 20)
524[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 +0000525
Tim Petersf6ed0742001-06-27 07:17:57 +0000526
Tim Petersb9e9ff12001-06-24 03:44:52 +0000527Another famous problem: generate all integers of the form
528 2**i * 3**j * 5**k
529in increasing order, where i,j,k >= 0. Trickier than it may look at first!
530Try writing it without generators, and correctly, and without generating
5313 internal results for each result output.
532
533>>> def times(n, g):
534... for i in g:
535... yield n * i
536>>> firstn(times(10, intsfrom(1)), 10)
537[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
538
539>>> def merge(g, h):
Georg Brandla18af4e2007-04-21 15:47:16 +0000540... ng = next(g)
541... nh = next(h)
Tim Petersb9e9ff12001-06-24 03:44:52 +0000542... while 1:
543... if ng < nh:
544... yield ng
Georg Brandla18af4e2007-04-21 15:47:16 +0000545... ng = next(g)
Tim Petersb9e9ff12001-06-24 03:44:52 +0000546... elif ng > nh:
547... yield nh
Georg Brandla18af4e2007-04-21 15:47:16 +0000548... nh = next(h)
Tim Petersb9e9ff12001-06-24 03:44:52 +0000549... else:
550... yield ng
Georg Brandla18af4e2007-04-21 15:47:16 +0000551... ng = next(g)
552... nh = next(h)
Tim Petersb9e9ff12001-06-24 03:44:52 +0000553
Tim Petersf6ed0742001-06-27 07:17:57 +0000554The following works, but is doing a whale of a lot of redundant work --
555it's not clear how to get the internal uses of m235 to share a single
556generator. Note that me_times2 (etc) each need to see every element in the
557result sequence. So this is an example where lazy lists are more natural
558(you can look at the head of a lazy list any number of times).
Tim Petersb9e9ff12001-06-24 03:44:52 +0000559
560>>> def m235():
561... yield 1
562... me_times2 = times(2, m235())
563... me_times3 = times(3, m235())
564... me_times5 = times(5, m235())
565... for i in merge(merge(me_times2,
566... me_times3),
567... me_times5):
568... yield i
569
Tim Petersf6ed0742001-06-27 07:17:57 +0000570Don't print "too many" of these -- the implementation above is extremely
571inefficient: each call of m235() leads to 3 recursive calls, and in
572turn each of those 3 more, and so on, and so on, until we've descended
573enough levels to satisfy the print stmts. Very odd: when I printed 5
574lines of results below, this managed to screw up Win98's malloc in "the
575usual" way, i.e. the heap grew over 4Mb so Win98 started fragmenting
576address space, and it *looked* like a very slow leak.
577
Tim Petersb9e9ff12001-06-24 03:44:52 +0000578>>> result = m235()
Tim Petersf6ed0742001-06-27 07:17:57 +0000579>>> for i in range(3):
Guido van Rossum7131f842007-02-09 20:13:25 +0000580... print(firstn(result, 15))
Tim Petersb9e9ff12001-06-24 03:44:52 +0000581[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
582[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
583[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
Tim Petersee309272001-06-24 05:47:06 +0000584
585Heh. Here's one way to get a shared list, complete with an excruciating
586namespace renaming trick. The *pretty* part is that the times() and merge()
587functions can be reused as-is, because they only assume their stream
588arguments are iterable -- a LazyList is the same as a generator to times().
589
590>>> class LazyList:
591... def __init__(self, g):
592... self.sofar = []
Georg Brandla18af4e2007-04-21 15:47:16 +0000593... self.fetch = g.__next__
Tim Petersee309272001-06-24 05:47:06 +0000594...
595... def __getitem__(self, i):
596... sofar, fetch = self.sofar, self.fetch
597... while i >= len(sofar):
598... sofar.append(fetch())
599... return sofar[i]
600
601>>> def m235():
602... yield 1
Tim Petersea2e97a2001-06-24 07:10:02 +0000603... # Gack: m235 below actually refers to a LazyList.
Tim Petersee309272001-06-24 05:47:06 +0000604... me_times2 = times(2, m235)
605... me_times3 = times(3, m235)
606... me_times5 = times(5, m235)
607... for i in merge(merge(me_times2,
608... me_times3),
609... me_times5):
610... yield i
611
Tim Petersf6ed0742001-06-27 07:17:57 +0000612Print as many of these as you like -- *this* implementation is memory-
Neil Schemenauerb20e9db2001-07-12 13:26:41 +0000613efficient.
Tim Petersf6ed0742001-06-27 07:17:57 +0000614
Tim Petersee309272001-06-24 05:47:06 +0000615>>> m235 = LazyList(m235())
616>>> for i in range(5):
Guido van Rossum7131f842007-02-09 20:13:25 +0000617... print([m235[j] for j in range(15*i, 15*(i+1))])
Tim Petersee309272001-06-24 05:47:06 +0000618[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
619[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
620[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
621[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
622[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Tim Petersf6ed0742001-06-27 07:17:57 +0000623
Tim Petersf6ed0742001-06-27 07:17:57 +0000624Ye olde Fibonacci generator, LazyList style.
625
626>>> def fibgen(a, b):
627...
628... def sum(g, h):
629... while 1:
Georg Brandla18af4e2007-04-21 15:47:16 +0000630... yield next(g) + next(h)
Tim Petersf6ed0742001-06-27 07:17:57 +0000631...
632... def tail(g):
Georg Brandla18af4e2007-04-21 15:47:16 +0000633... next(g) # throw first away
Tim Petersf6ed0742001-06-27 07:17:57 +0000634... for x in g:
635... yield x
636...
637... yield a
638... yield b
639... for s in sum(iter(fib),
640... tail(iter(fib))):
641... yield s
642
643>>> fib = LazyList(fibgen(1, 2))
644>>> firstn(iter(fib), 17)
645[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
Georg Brandl52715f62005-08-24 09:02:29 +0000646
647
648Running after your tail with itertools.tee (new in version 2.4)
649
650The algorithms "m235" (Hamming) and Fibonacci presented above are both
651examples of a whole family of FP (functional programming) algorithms
652where a function produces and returns a list while the production algorithm
653suppose the list as already produced by recursively calling itself.
654For these algorithms to work, they must:
655
656- produce at least a first element without presupposing the existence of
657 the rest of the list
658- produce their elements in a lazy manner
659
660To work efficiently, the beginning of the list must not be recomputed over
661and over again. This is ensured in most FP languages as a built-in feature.
662In python, we have to explicitly maintain a list of already computed results
663and abandon genuine recursivity.
664
665This is what had been attempted above with the LazyList class. One problem
666with that class is that it keeps a list of all of the generated results and
667therefore continually grows. This partially defeats the goal of the generator
668concept, viz. produce the results only as needed instead of producing them
669all and thereby wasting memory.
670
671Thanks to itertools.tee, it is now clear "how to get the internal uses of
672m235 to share a single generator".
673
674>>> from itertools import tee
675>>> def m235():
676... def _m235():
677... yield 1
678... for n in merge(times(2, m2),
679... merge(times(3, m3),
680... times(5, m5))):
681... yield n
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000682... m1 = _m235()
683... m2, m3, m5, mRes = tee(m1, 4)
Georg Brandl52715f62005-08-24 09:02:29 +0000684... return mRes
685
686>>> it = m235()
687>>> for i in range(5):
Guido van Rossum7131f842007-02-09 20:13:25 +0000688... print(firstn(it, 15))
Georg Brandl52715f62005-08-24 09:02:29 +0000689[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
690[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
691[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
692[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
693[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
694
695The "tee" function does just what we want. It internally keeps a generated
696result for as long as it has not been "consumed" from all of the duplicated
697iterators, whereupon it is deleted. You can therefore print the hamming
698sequence during hours without increasing memory usage, or very little.
699
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000700The beauty of it is that recursive running-after-their-tail FP algorithms
Georg Brandl52715f62005-08-24 09:02:29 +0000701are quite straightforwardly expressed with this Python idiom.
702
Georg Brandl52715f62005-08-24 09:02:29 +0000703Ye olde Fibonacci generator, tee style.
704
705>>> def fib():
Tim Peters9e34c042005-08-26 15:20:46 +0000706...
Georg Brandl52715f62005-08-24 09:02:29 +0000707... def _isum(g, h):
708... while 1:
Georg Brandla18af4e2007-04-21 15:47:16 +0000709... yield next(g) + next(h)
Tim Peters9e34c042005-08-26 15:20:46 +0000710...
Georg Brandl52715f62005-08-24 09:02:29 +0000711... def _fib():
712... yield 1
713... yield 2
Georg Brandla18af4e2007-04-21 15:47:16 +0000714... next(fibTail) # throw first away
Georg Brandl52715f62005-08-24 09:02:29 +0000715... for res in _isum(fibHead, fibTail):
716... yield res
Tim Peters9e34c042005-08-26 15:20:46 +0000717...
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000718... realfib = _fib()
719... fibHead, fibTail, fibRes = tee(realfib, 3)
Georg Brandl52715f62005-08-24 09:02:29 +0000720... return fibRes
721
722>>> firstn(fib(), 17)
723[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
724
Tim Peters0f9da0a2001-06-23 21:01:47 +0000725"""
726
Tim Petersb6c3cea2001-06-26 03:36:28 +0000727# syntax_tests mostly provokes SyntaxErrors. Also fiddling with #if 0
728# hackery.
Tim Petersee309272001-06-24 05:47:06 +0000729
Tim Petersea2e97a2001-06-24 07:10:02 +0000730syntax_tests = """
731
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000732These are fine:
Tim Petersea2e97a2001-06-24 07:10:02 +0000733
734>>> def f():
735... yield 1
736... return
737
Tim Petersaef8cfa2004-08-27 15:12:49 +0000738>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000739... try:
740... yield 1
741... finally:
742... pass
Tim Petersea2e97a2001-06-24 07:10:02 +0000743
Tim Petersaef8cfa2004-08-27 15:12:49 +0000744>>> def f():
Tim Petersea2e97a2001-06-24 07:10:02 +0000745... try:
746... try:
Tim Peters3caca232001-12-06 06:23:26 +0000747... 1//0
Tim Petersea2e97a2001-06-24 07:10:02 +0000748... except ZeroDivisionError:
Tim Peters536cf992005-12-25 23:18:31 +0000749... yield 666
Tim Petersea2e97a2001-06-24 07:10:02 +0000750... except:
751... pass
752... finally:
753... pass
Tim Petersea2e97a2001-06-24 07:10:02 +0000754
755>>> def f():
756... try:
757... try:
758... yield 12
Tim Peters3caca232001-12-06 06:23:26 +0000759... 1//0
Tim Petersea2e97a2001-06-24 07:10:02 +0000760... except ZeroDivisionError:
761... yield 666
762... except:
763... try:
764... x = 12
765... finally:
766... yield 12
767... except:
768... return
769>>> list(f())
770[12, 666]
Tim Petersb6c3cea2001-06-26 03:36:28 +0000771
772>>> def f():
Tim Peters08a898f2001-06-28 01:52:22 +0000773... yield
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000774>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000775<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000776
Tim Peters08a898f2001-06-28 01:52:22 +0000777
778>>> def f():
779... if 0:
780... yield
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000781>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000782<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +0000783
Tim Peters08a898f2001-06-28 01:52:22 +0000784
785>>> def f():
Tim Petersb6c3cea2001-06-26 03:36:28 +0000786... if 0:
787... yield 1
788>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000789<class 'generator'>
Tim Petersb6c3cea2001-06-26 03:36:28 +0000790
791>>> def f():
792... if "":
793... yield None
794>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000795<class 'generator'>
Tim Petersb6c3cea2001-06-26 03:36:28 +0000796
797>>> def f():
798... return
799... try:
800... if x==4:
801... pass
802... elif 0:
803... try:
Tim Peters3caca232001-12-06 06:23:26 +0000804... 1//0
Tim Petersb6c3cea2001-06-26 03:36:28 +0000805... except SyntaxError:
806... pass
807... else:
808... if 0:
809... while 12:
810... x += 1
811... yield 2 # don't blink
812... f(a, b, c, d, e)
813... else:
814... pass
815... except:
816... x = 1
817... return
818>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000819<class 'generator'>
Tim Petersb6c3cea2001-06-26 03:36:28 +0000820
821>>> def f():
822... if 0:
823... def g():
824... yield 1
825...
826>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000827<class 'NoneType'>
Tim Petersb6c3cea2001-06-26 03:36:28 +0000828
829>>> def f():
830... if 0:
831... class C:
832... def __init__(self):
833... yield 1
834... def f(self):
835... yield 2
836>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000837<class 'NoneType'>
Tim Peters08a898f2001-06-28 01:52:22 +0000838
839>>> def f():
840... if 0:
841... return
842... if 0:
843... yield 2
844>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +0000845<class 'generator'>
Tim Peters08a898f2001-06-28 01:52:22 +0000846
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +0000847This one caused a crash (see SF bug 567538):
848
849>>> def f():
850... for i in range(3):
851... try:
852... continue
853... finally:
854... yield i
Tim Petersc411dba2002-07-16 21:35:23 +0000855...
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +0000856>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +0000857>>> print(next(g))
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +00008580
Georg Brandla18af4e2007-04-21 15:47:16 +0000859>>> print(next(g))
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +00008601
Georg Brandla18af4e2007-04-21 15:47:16 +0000861>>> print(next(g))
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +00008622
Georg Brandla18af4e2007-04-21 15:47:16 +0000863>>> print(next(g))
Guido van Rossumc5fe5eb2002-06-12 03:45:21 +0000864Traceback (most recent call last):
865StopIteration
Christian Heimesaf98da12008-01-27 15:18:18 +0000866
867
868Test the gi_code attribute
869
870>>> def f():
871... yield 5
872...
873>>> g = f()
874>>> g.gi_code is f.__code__
875True
876>>> next(g)
8775
878>>> next(g)
879Traceback (most recent call last):
880StopIteration
881>>> g.gi_code is f.__code__
882True
883
Alexandre Vassalottie9f305f2008-05-16 04:39:54 +0000884
885Test the __name__ attribute and the repr()
886
887>>> def f():
888... yield 5
889...
890>>> g = f()
891>>> g.__name__
892'f'
893>>> repr(g) # doctest: +ELLIPSIS
Alexandre Vassalottibee32532008-05-16 18:15:12 +0000894'<generator object f at ...>'
Benjamin Peterson371ccfb2008-12-27 19:03:36 +0000895
896Lambdas shouldn't have their usual return behavior.
897
898>>> x = lambda: (yield 1)
899>>> list(x())
900[1]
901
902>>> x = lambda: ((yield 1), (yield 2))
903>>> list(x())
904[1, 2]
Tim Petersea2e97a2001-06-24 07:10:02 +0000905"""
906
Tim Petersbe4f0a72001-06-29 02:41:16 +0000907# conjoin is a simple backtracking generator, named in honor of Icon's
908# "conjunction" control structure. Pass a list of no-argument functions
909# that return iterable objects. Easiest to explain by example: assume the
910# function list [x, y, z] is passed. Then conjoin acts like:
911#
912# def g():
913# values = [None] * 3
914# for values[0] in x():
915# for values[1] in y():
916# for values[2] in z():
917# yield values
918#
919# So some 3-lists of values *may* be generated, each time we successfully
920# get into the innermost loop. If an iterator fails (is exhausted) before
921# then, it "backtracks" to get the next value from the nearest enclosing
922# iterator (the one "to the left"), and starts all over again at the next
923# slot (pumps a fresh iterator). Of course this is most useful when the
924# iterators have side-effects, so that which values *can* be generated at
925# each slot depend on the values iterated at previous slots.
926
Benjamin Peterson78565b22009-06-28 19:19:51 +0000927def simple_conjoin(gs):
Tim Petersbe4f0a72001-06-29 02:41:16 +0000928
929 values = [None] * len(gs)
930
Benjamin Peterson78565b22009-06-28 19:19:51 +0000931 def gen(i):
Tim Petersbe4f0a72001-06-29 02:41:16 +0000932 if i >= len(gs):
933 yield values
934 else:
935 for values[i] in gs[i]():
936 for x in gen(i+1):
937 yield x
938
939 for x in gen(0):
940 yield x
941
Tim Petersc468fd22001-06-30 07:29:44 +0000942# That works fine, but recursing a level and checking i against len(gs) for
943# each item produced is inefficient. By doing manual loop unrolling across
944# generator boundaries, it's possible to eliminate most of that overhead.
945# This isn't worth the bother *in general* for generators, but conjoin() is
946# a core building block for some CPU-intensive generator applications.
947
948def conjoin(gs):
949
950 n = len(gs)
951 values = [None] * n
952
953 # Do one loop nest at time recursively, until the # of loop nests
954 # remaining is divisible by 3.
955
Benjamin Peterson78565b22009-06-28 19:19:51 +0000956 def gen(i):
Tim Petersc468fd22001-06-30 07:29:44 +0000957 if i >= n:
958 yield values
959
960 elif (n-i) % 3:
961 ip1 = i+1
962 for values[i] in gs[i]():
963 for x in gen(ip1):
964 yield x
965
966 else:
967 for x in _gen3(i):
968 yield x
969
970 # Do three loop nests at a time, recursing only if at least three more
971 # remain. Don't call directly: this is an internal optimization for
972 # gen's use.
973
Benjamin Peterson78565b22009-06-28 19:19:51 +0000974 def _gen3(i):
Tim Petersc468fd22001-06-30 07:29:44 +0000975 assert i < n and (n-i) % 3 == 0
976 ip1, ip2, ip3 = i+1, i+2, i+3
977 g, g1, g2 = gs[i : ip3]
978
979 if ip3 >= n:
980 # These are the last three, so we can yield values directly.
981 for values[i] in g():
982 for values[ip1] in g1():
983 for values[ip2] in g2():
984 yield values
985
986 else:
987 # At least 6 loop nests remain; peel off 3 and recurse for the
988 # rest.
989 for values[i] in g():
990 for values[ip1] in g1():
991 for values[ip2] in g2():
992 for x in _gen3(ip3):
993 yield x
994
995 for x in gen(0):
996 yield x
997
unknown31569562001-07-04 22:11:22 +0000998# And one more approach: For backtracking apps like the Knight's Tour
999# solver below, the number of backtracking levels can be enormous (one
1000# level per square, for the Knight's Tour, so that e.g. a 100x100 board
1001# needs 10,000 levels). In such cases Python is likely to run out of
1002# stack space due to recursion. So here's a recursion-free version of
1003# conjoin too.
1004# NOTE WELL: This allows large problems to be solved with only trivial
1005# demands on stack space. Without explicitly resumable generators, this is
Tim Peters9a8c8e22001-07-13 09:12:12 +00001006# much harder to achieve. OTOH, this is much slower (up to a factor of 2)
1007# than the fancy unrolled recursive conjoin.
unknown31569562001-07-04 22:11:22 +00001008
1009def flat_conjoin(gs): # rename to conjoin to run tests with this instead
1010 n = len(gs)
1011 values = [None] * n
1012 iters = [None] * n
Tim Peters9a8c8e22001-07-13 09:12:12 +00001013 _StopIteration = StopIteration # make local because caught a *lot*
unknown31569562001-07-04 22:11:22 +00001014 i = 0
Tim Peters9a8c8e22001-07-13 09:12:12 +00001015 while 1:
1016 # Descend.
1017 try:
1018 while i < n:
Georg Brandla18af4e2007-04-21 15:47:16 +00001019 it = iters[i] = gs[i]().__next__
Tim Peters9a8c8e22001-07-13 09:12:12 +00001020 values[i] = it()
1021 i += 1
1022 except _StopIteration:
1023 pass
unknown31569562001-07-04 22:11:22 +00001024 else:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001025 assert i == n
1026 yield values
unknown31569562001-07-04 22:11:22 +00001027
Tim Peters9a8c8e22001-07-13 09:12:12 +00001028 # Backtrack until an older iterator can be resumed.
1029 i -= 1
unknown31569562001-07-04 22:11:22 +00001030 while i >= 0:
1031 try:
1032 values[i] = iters[i]()
Tim Peters9a8c8e22001-07-13 09:12:12 +00001033 # Success! Start fresh at next level.
unknown31569562001-07-04 22:11:22 +00001034 i += 1
1035 break
Tim Peters9a8c8e22001-07-13 09:12:12 +00001036 except _StopIteration:
1037 # Continue backtracking.
1038 i -= 1
1039 else:
1040 assert i < 0
1041 break
unknown31569562001-07-04 22:11:22 +00001042
Tim Petersbe4f0a72001-06-29 02:41:16 +00001043# A conjoin-based N-Queens solver.
1044
1045class Queens:
1046 def __init__(self, n):
1047 self.n = n
1048 rangen = range(n)
1049
1050 # Assign a unique int to each column and diagonal.
1051 # columns: n of those, range(n).
1052 # NW-SE diagonals: 2n-1 of these, i-j unique and invariant along
1053 # each, smallest i-j is 0-(n-1) = 1-n, so add n-1 to shift to 0-
1054 # based.
1055 # NE-SW diagonals: 2n-1 of these, i+j unique and invariant along
1056 # each, smallest i+j is 0, largest is 2n-2.
1057
1058 # For each square, compute a bit vector of the columns and
1059 # diagonals it covers, and for each row compute a function that
1060 # generates the possiblities for the columns in that row.
1061 self.rowgenerators = []
1062 for i in rangen:
Guido van Rossume2a383d2007-01-15 16:59:06 +00001063 rowuses = [(1 << j) | # column ordinal
1064 (1 << (n + i-j + n-1)) | # NW-SE ordinal
1065 (1 << (n + 2*n-1 + i+j)) # NE-SW ordinal
Tim Petersbe4f0a72001-06-29 02:41:16 +00001066 for j in rangen]
1067
1068 def rowgen(rowuses=rowuses):
1069 for j in rangen:
1070 uses = rowuses[j]
Tim Petersc468fd22001-06-30 07:29:44 +00001071 if uses & self.used == 0:
1072 self.used |= uses
1073 yield j
1074 self.used &= ~uses
Tim Petersbe4f0a72001-06-29 02:41:16 +00001075
1076 self.rowgenerators.append(rowgen)
1077
1078 # Generate solutions.
1079 def solve(self):
1080 self.used = 0
1081 for row2col in conjoin(self.rowgenerators):
1082 yield row2col
1083
1084 def printsolution(self, row2col):
1085 n = self.n
1086 assert n == len(row2col)
1087 sep = "+" + "-+" * n
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001088 print(sep)
Tim Petersbe4f0a72001-06-29 02:41:16 +00001089 for i in range(n):
1090 squares = [" " for j in range(n)]
1091 squares[row2col[i]] = "Q"
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001092 print("|" + "|".join(squares) + "|")
1093 print(sep)
Tim Petersbe4f0a72001-06-29 02:41:16 +00001094
unknown31569562001-07-04 22:11:22 +00001095# A conjoin-based Knight's Tour solver. This is pretty sophisticated
1096# (e.g., when used with flat_conjoin above, and passing hard=1 to the
1097# constructor, a 200x200 Knight's Tour was found quickly -- note that we're
Tim Peters9a8c8e22001-07-13 09:12:12 +00001098# creating 10s of thousands of generators then!), and is lengthy.
unknown31569562001-07-04 22:11:22 +00001099
1100class Knights:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001101 def __init__(self, m, n, hard=0):
1102 self.m, self.n = m, n
unknown31569562001-07-04 22:11:22 +00001103
Tim Peters9a8c8e22001-07-13 09:12:12 +00001104 # solve() will set up succs[i] to be a list of square #i's
1105 # successors.
1106 succs = self.succs = []
unknown31569562001-07-04 22:11:22 +00001107
Tim Peters9a8c8e22001-07-13 09:12:12 +00001108 # Remove i0 from each of its successor's successor lists, i.e.
1109 # successors can't go back to i0 again. Return 0 if we can
1110 # detect this makes a solution impossible, else return 1.
unknown31569562001-07-04 22:11:22 +00001111
Tim Peters9a8c8e22001-07-13 09:12:12 +00001112 def remove_from_successors(i0, len=len):
unknown31569562001-07-04 22:11:22 +00001113 # If we remove all exits from a free square, we're dead:
1114 # even if we move to it next, we can't leave it again.
1115 # If we create a square with one exit, we must visit it next;
1116 # else somebody else will have to visit it, and since there's
1117 # only one adjacent, there won't be a way to leave it again.
1118 # Finelly, if we create more than one free square with a
1119 # single exit, we can only move to one of them next, leaving
1120 # the other one a dead end.
1121 ne0 = ne1 = 0
1122 for i in succs[i0]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001123 s = succs[i]
1124 s.remove(i0)
1125 e = len(s)
1126 if e == 0:
1127 ne0 += 1
1128 elif e == 1:
1129 ne1 += 1
unknown31569562001-07-04 22:11:22 +00001130 return ne0 == 0 and ne1 < 2
1131
Tim Peters9a8c8e22001-07-13 09:12:12 +00001132 # Put i0 back in each of its successor's successor lists.
1133
1134 def add_to_successors(i0):
unknown31569562001-07-04 22:11:22 +00001135 for i in succs[i0]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001136 succs[i].append(i0)
unknown31569562001-07-04 22:11:22 +00001137
1138 # Generate the first move.
1139 def first():
Tim Peters9a8c8e22001-07-13 09:12:12 +00001140 if m < 1 or n < 1:
unknown31569562001-07-04 22:11:22 +00001141 return
1142
unknown31569562001-07-04 22:11:22 +00001143 # Since we're looking for a cycle, it doesn't matter where we
1144 # start. Starting in a corner makes the 2nd move easy.
Tim Peters9a8c8e22001-07-13 09:12:12 +00001145 corner = self.coords2index(0, 0)
1146 remove_from_successors(corner)
unknown31569562001-07-04 22:11:22 +00001147 self.lastij = corner
1148 yield corner
Tim Peters9a8c8e22001-07-13 09:12:12 +00001149 add_to_successors(corner)
unknown31569562001-07-04 22:11:22 +00001150
1151 # Generate the second moves.
1152 def second():
Tim Peters9a8c8e22001-07-13 09:12:12 +00001153 corner = self.coords2index(0, 0)
unknown31569562001-07-04 22:11:22 +00001154 assert self.lastij == corner # i.e., we started in the corner
Tim Peters9a8c8e22001-07-13 09:12:12 +00001155 if m < 3 or n < 3:
unknown31569562001-07-04 22:11:22 +00001156 return
Tim Peters9a8c8e22001-07-13 09:12:12 +00001157 assert len(succs[corner]) == 2
1158 assert self.coords2index(1, 2) in succs[corner]
1159 assert self.coords2index(2, 1) in succs[corner]
unknown31569562001-07-04 22:11:22 +00001160 # Only two choices. Whichever we pick, the other must be the
Tim Peters9a8c8e22001-07-13 09:12:12 +00001161 # square picked on move m*n, as it's the only way to get back
unknown31569562001-07-04 22:11:22 +00001162 # to (0, 0). Save its index in self.final so that moves before
1163 # the last know it must be kept free.
1164 for i, j in (1, 2), (2, 1):
Tim Peters9a8c8e22001-07-13 09:12:12 +00001165 this = self.coords2index(i, j)
1166 final = self.coords2index(3-i, 3-j)
unknown31569562001-07-04 22:11:22 +00001167 self.final = final
unknown31569562001-07-04 22:11:22 +00001168
Tim Peters9a8c8e22001-07-13 09:12:12 +00001169 remove_from_successors(this)
1170 succs[final].append(corner)
unknown31569562001-07-04 22:11:22 +00001171 self.lastij = this
1172 yield this
Tim Peters9a8c8e22001-07-13 09:12:12 +00001173 succs[final].remove(corner)
1174 add_to_successors(this)
unknown31569562001-07-04 22:11:22 +00001175
Tim Peters9a8c8e22001-07-13 09:12:12 +00001176 # Generate moves 3 thru m*n-1.
1177 def advance(len=len):
unknown31569562001-07-04 22:11:22 +00001178 # If some successor has only one exit, must take it.
1179 # Else favor successors with fewer exits.
1180 candidates = []
1181 for i in succs[self.lastij]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001182 e = len(succs[i])
1183 assert e > 0, "else remove_from_successors() pruning flawed"
1184 if e == 1:
1185 candidates = [(e, i)]
1186 break
1187 candidates.append((e, i))
unknown31569562001-07-04 22:11:22 +00001188 else:
1189 candidates.sort()
1190
1191 for e, i in candidates:
1192 if i != self.final:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001193 if remove_from_successors(i):
unknown31569562001-07-04 22:11:22 +00001194 self.lastij = i
1195 yield i
Tim Peters9a8c8e22001-07-13 09:12:12 +00001196 add_to_successors(i)
unknown31569562001-07-04 22:11:22 +00001197
Tim Peters9a8c8e22001-07-13 09:12:12 +00001198 # Generate moves 3 thru m*n-1. Alternative version using a
unknown31569562001-07-04 22:11:22 +00001199 # stronger (but more expensive) heuristic to order successors.
Tim Peters9a8c8e22001-07-13 09:12:12 +00001200 # Since the # of backtracking levels is m*n, a poor move early on
1201 # can take eons to undo. Smallest square board for which this
1202 # matters a lot is 52x52.
1203 def advance_hard(vmid=(m-1)/2.0, hmid=(n-1)/2.0, len=len):
unknown31569562001-07-04 22:11:22 +00001204 # If some successor has only one exit, must take it.
1205 # Else favor successors with fewer exits.
1206 # Break ties via max distance from board centerpoint (favor
1207 # corners and edges whenever possible).
1208 candidates = []
1209 for i in succs[self.lastij]:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001210 e = len(succs[i])
1211 assert e > 0, "else remove_from_successors() pruning flawed"
1212 if e == 1:
1213 candidates = [(e, 0, i)]
1214 break
1215 i1, j1 = self.index2coords(i)
1216 d = (i1 - vmid)**2 + (j1 - hmid)**2
1217 candidates.append((e, -d, i))
unknown31569562001-07-04 22:11:22 +00001218 else:
1219 candidates.sort()
1220
1221 for e, d, i in candidates:
1222 if i != self.final:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001223 if remove_from_successors(i):
unknown31569562001-07-04 22:11:22 +00001224 self.lastij = i
1225 yield i
Tim Peters9a8c8e22001-07-13 09:12:12 +00001226 add_to_successors(i)
unknown31569562001-07-04 22:11:22 +00001227
1228 # Generate the last move.
1229 def last():
1230 assert self.final in succs[self.lastij]
1231 yield self.final
1232
Tim Peters9a8c8e22001-07-13 09:12:12 +00001233 if m*n < 4:
1234 self.squaregenerators = [first]
unknown31569562001-07-04 22:11:22 +00001235 else:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001236 self.squaregenerators = [first, second] + \
1237 [hard and advance_hard or advance] * (m*n - 3) + \
unknown31569562001-07-04 22:11:22 +00001238 [last]
1239
Tim Peters9a8c8e22001-07-13 09:12:12 +00001240 def coords2index(self, i, j):
1241 assert 0 <= i < self.m
1242 assert 0 <= j < self.n
1243 return i * self.n + j
1244
1245 def index2coords(self, index):
1246 assert 0 <= index < self.m * self.n
1247 return divmod(index, self.n)
1248
1249 def _init_board(self):
1250 succs = self.succs
1251 del succs[:]
1252 m, n = self.m, self.n
1253 c2i = self.coords2index
1254
1255 offsets = [( 1, 2), ( 2, 1), ( 2, -1), ( 1, -2),
1256 (-1, -2), (-2, -1), (-2, 1), (-1, 2)]
1257 rangen = range(n)
1258 for i in range(m):
1259 for j in rangen:
1260 s = [c2i(i+io, j+jo) for io, jo in offsets
1261 if 0 <= i+io < m and
1262 0 <= j+jo < n]
1263 succs.append(s)
1264
unknown31569562001-07-04 22:11:22 +00001265 # Generate solutions.
1266 def solve(self):
Tim Peters9a8c8e22001-07-13 09:12:12 +00001267 self._init_board()
1268 for x in conjoin(self.squaregenerators):
unknown31569562001-07-04 22:11:22 +00001269 yield x
1270
1271 def printsolution(self, x):
Tim Peters9a8c8e22001-07-13 09:12:12 +00001272 m, n = self.m, self.n
1273 assert len(x) == m*n
1274 w = len(str(m*n))
unknown31569562001-07-04 22:11:22 +00001275 format = "%" + str(w) + "d"
1276
Tim Peters9a8c8e22001-07-13 09:12:12 +00001277 squares = [[None] * n for i in range(m)]
unknown31569562001-07-04 22:11:22 +00001278 k = 1
1279 for i in x:
Tim Peters9a8c8e22001-07-13 09:12:12 +00001280 i1, j1 = self.index2coords(i)
unknown31569562001-07-04 22:11:22 +00001281 squares[i1][j1] = format % k
1282 k += 1
1283
1284 sep = "+" + ("-" * w + "+") * n
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001285 print(sep)
Tim Peters9a8c8e22001-07-13 09:12:12 +00001286 for i in range(m):
unknown31569562001-07-04 22:11:22 +00001287 row = squares[i]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001288 print("|" + "|".join(row) + "|")
1289 print(sep)
unknown31569562001-07-04 22:11:22 +00001290
Tim Petersbe4f0a72001-06-29 02:41:16 +00001291conjoin_tests = """
1292
1293Generate the 3-bit binary numbers in order. This illustrates dumbest-
1294possible use of conjoin, just to generate the full cross-product.
1295
unknown31569562001-07-04 22:11:22 +00001296>>> for c in conjoin([lambda: iter((0, 1))] * 3):
Guido van Rossum7131f842007-02-09 20:13:25 +00001297... print(c)
Tim Petersbe4f0a72001-06-29 02:41:16 +00001298[0, 0, 0]
1299[0, 0, 1]
1300[0, 1, 0]
1301[0, 1, 1]
1302[1, 0, 0]
1303[1, 0, 1]
1304[1, 1, 0]
1305[1, 1, 1]
1306
Tim Petersc468fd22001-06-30 07:29:44 +00001307For efficiency in typical backtracking apps, conjoin() yields the same list
1308object each time. So if you want to save away a full account of its
1309generated sequence, you need to copy its results.
1310
1311>>> def gencopy(iterator):
1312... for x in iterator:
1313... yield x[:]
1314
1315>>> for n in range(10):
unknown31569562001-07-04 22:11:22 +00001316... all = list(gencopy(conjoin([lambda: iter((0, 1))] * n)))
Guido van Rossum7131f842007-02-09 20:13:25 +00001317... print(n, len(all), all[0] == [0] * n, all[-1] == [1] * n)
Guido van Rossum77f6a652002-04-03 22:41:51 +000013180 1 True True
13191 2 True True
13202 4 True True
13213 8 True True
13224 16 True True
13235 32 True True
13246 64 True True
13257 128 True True
13268 256 True True
13279 512 True True
Tim Petersc468fd22001-06-30 07:29:44 +00001328
Tim Petersbe4f0a72001-06-29 02:41:16 +00001329And run an 8-queens solver.
1330
1331>>> q = Queens(8)
1332>>> LIMIT = 2
1333>>> count = 0
1334>>> for row2col in q.solve():
1335... count += 1
1336... if count <= LIMIT:
Guido van Rossum7131f842007-02-09 20:13:25 +00001337... print("Solution", count)
Tim Petersbe4f0a72001-06-29 02:41:16 +00001338... q.printsolution(row2col)
1339Solution 1
1340+-+-+-+-+-+-+-+-+
1341|Q| | | | | | | |
1342+-+-+-+-+-+-+-+-+
1343| | | | |Q| | | |
1344+-+-+-+-+-+-+-+-+
1345| | | | | | | |Q|
1346+-+-+-+-+-+-+-+-+
1347| | | | | |Q| | |
1348+-+-+-+-+-+-+-+-+
1349| | |Q| | | | | |
1350+-+-+-+-+-+-+-+-+
1351| | | | | | |Q| |
1352+-+-+-+-+-+-+-+-+
1353| |Q| | | | | | |
1354+-+-+-+-+-+-+-+-+
1355| | | |Q| | | | |
1356+-+-+-+-+-+-+-+-+
1357Solution 2
1358+-+-+-+-+-+-+-+-+
1359|Q| | | | | | | |
1360+-+-+-+-+-+-+-+-+
1361| | | | | |Q| | |
1362+-+-+-+-+-+-+-+-+
1363| | | | | | | |Q|
1364+-+-+-+-+-+-+-+-+
1365| | |Q| | | | | |
1366+-+-+-+-+-+-+-+-+
1367| | | | | | |Q| |
1368+-+-+-+-+-+-+-+-+
1369| | | |Q| | | | |
1370+-+-+-+-+-+-+-+-+
1371| |Q| | | | | | |
1372+-+-+-+-+-+-+-+-+
1373| | | | |Q| | | |
1374+-+-+-+-+-+-+-+-+
1375
Guido van Rossum7131f842007-02-09 20:13:25 +00001376>>> print(count, "solutions in all.")
Tim Petersbe4f0a72001-06-29 02:41:16 +0000137792 solutions in all.
unknown31569562001-07-04 22:11:22 +00001378
1379And run a Knight's Tour on a 10x10 board. Note that there are about
138020,000 solutions even on a 6x6 board, so don't dare run this to exhaustion.
1381
Tim Peters9a8c8e22001-07-13 09:12:12 +00001382>>> k = Knights(10, 10)
unknown31569562001-07-04 22:11:22 +00001383>>> LIMIT = 2
1384>>> count = 0
1385>>> for x in k.solve():
1386... count += 1
1387... if count <= LIMIT:
Guido van Rossum7131f842007-02-09 20:13:25 +00001388... print("Solution", count)
unknown31569562001-07-04 22:11:22 +00001389... k.printsolution(x)
1390... else:
1391... break
1392Solution 1
1393+---+---+---+---+---+---+---+---+---+---+
1394| 1| 58| 27| 34| 3| 40| 29| 10| 5| 8|
1395+---+---+---+---+---+---+---+---+---+---+
1396| 26| 35| 2| 57| 28| 33| 4| 7| 30| 11|
1397+---+---+---+---+---+---+---+---+---+---+
1398| 59|100| 73| 36| 41| 56| 39| 32| 9| 6|
1399+---+---+---+---+---+---+---+---+---+---+
1400| 74| 25| 60| 55| 72| 37| 42| 49| 12| 31|
1401+---+---+---+---+---+---+---+---+---+---+
1402| 61| 86| 99| 76| 63| 52| 47| 38| 43| 50|
1403+---+---+---+---+---+---+---+---+---+---+
1404| 24| 75| 62| 85| 54| 71| 64| 51| 48| 13|
1405+---+---+---+---+---+---+---+---+---+---+
1406| 87| 98| 91| 80| 77| 84| 53| 46| 65| 44|
1407+---+---+---+---+---+---+---+---+---+---+
1408| 90| 23| 88| 95| 70| 79| 68| 83| 14| 17|
1409+---+---+---+---+---+---+---+---+---+---+
1410| 97| 92| 21| 78| 81| 94| 19| 16| 45| 66|
1411+---+---+---+---+---+---+---+---+---+---+
1412| 22| 89| 96| 93| 20| 69| 82| 67| 18| 15|
1413+---+---+---+---+---+---+---+---+---+---+
1414Solution 2
1415+---+---+---+---+---+---+---+---+---+---+
1416| 1| 58| 27| 34| 3| 40| 29| 10| 5| 8|
1417+---+---+---+---+---+---+---+---+---+---+
1418| 26| 35| 2| 57| 28| 33| 4| 7| 30| 11|
1419+---+---+---+---+---+---+---+---+---+---+
1420| 59|100| 73| 36| 41| 56| 39| 32| 9| 6|
1421+---+---+---+---+---+---+---+---+---+---+
1422| 74| 25| 60| 55| 72| 37| 42| 49| 12| 31|
1423+---+---+---+---+---+---+---+---+---+---+
1424| 61| 86| 99| 76| 63| 52| 47| 38| 43| 50|
1425+---+---+---+---+---+---+---+---+---+---+
1426| 24| 75| 62| 85| 54| 71| 64| 51| 48| 13|
1427+---+---+---+---+---+---+---+---+---+---+
1428| 87| 98| 89| 80| 77| 84| 53| 46| 65| 44|
1429+---+---+---+---+---+---+---+---+---+---+
1430| 90| 23| 92| 95| 70| 79| 68| 83| 14| 17|
1431+---+---+---+---+---+---+---+---+---+---+
1432| 97| 88| 21| 78| 81| 94| 19| 16| 45| 66|
1433+---+---+---+---+---+---+---+---+---+---+
1434| 22| 91| 96| 93| 20| 69| 82| 67| 18| 15|
1435+---+---+---+---+---+---+---+---+---+---+
Tim Petersbe4f0a72001-06-29 02:41:16 +00001436"""
1437
Fred Drake56d12662002-08-09 18:37:10 +00001438weakref_tests = """\
1439Generators are weakly referencable:
1440
1441>>> import weakref
1442>>> def gen():
1443... yield 'foo!'
1444...
1445>>> wr = weakref.ref(gen)
1446>>> wr() is gen
1447True
1448>>> p = weakref.proxy(gen)
1449
1450Generator-iterators are weakly referencable as well:
1451
1452>>> gi = gen()
1453>>> wr = weakref.ref(gi)
1454>>> wr() is gi
1455True
1456>>> p = weakref.proxy(gi)
1457>>> list(p)
1458['foo!']
1459
1460"""
1461
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001462coroutine_tests = """\
1463Sending a value into a started generator:
1464
1465>>> def f():
Guido van Rossum7131f842007-02-09 20:13:25 +00001466... print((yield 1))
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001467... yield 2
1468>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001469>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +000014701
1471>>> g.send(42)
147242
14732
1474
1475Sending a value into a new generator produces a TypeError:
1476
1477>>> f().send("foo")
1478Traceback (most recent call last):
1479...
1480TypeError: can't send non-None value to a just-started generator
1481
1482
1483Yield by itself yields None:
1484
1485>>> def f(): yield
1486>>> list(f())
1487[None]
1488
1489
1490
1491An obscene abuse of a yield expression within a generator expression:
1492
1493>>> list((yield 21) for i in range(4))
1494[21, None, 21, None, 21, None, 21, None]
1495
1496And a more sane, but still weird usage:
1497
1498>>> def f(): list(i for i in [(yield 26)])
1499>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +00001500<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001501
1502
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001503A yield expression with augmented assignment.
1504
1505>>> def coroutine(seq):
1506... count = 0
1507... while count < 200:
1508... count += yield
1509... seq.append(count)
1510>>> seq = []
1511>>> c = coroutine(seq)
Georg Brandla18af4e2007-04-21 15:47:16 +00001512>>> next(c)
Guido van Rossum7131f842007-02-09 20:13:25 +00001513>>> print(seq)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001514[]
1515>>> c.send(10)
Guido van Rossum7131f842007-02-09 20:13:25 +00001516>>> print(seq)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001517[10]
1518>>> c.send(10)
Guido van Rossum7131f842007-02-09 20:13:25 +00001519>>> print(seq)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001520[10, 20]
1521>>> c.send(10)
Guido van Rossum7131f842007-02-09 20:13:25 +00001522>>> print(seq)
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001523[10, 20, 30]
1524
1525
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001526Check some syntax errors for yield expressions:
1527
1528>>> f=lambda: (yield 1),(yield 2)
1529Traceback (most recent call last):
1530 ...
Guido van Rossum33d26892007-08-05 15:29:28 +00001531SyntaxError: 'yield' outside function
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001532
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001533>>> def f(): x = yield = y
1534Traceback (most recent call last):
1535 ...
Guido van Rossum33d26892007-08-05 15:29:28 +00001536SyntaxError: assignment to yield expression not possible
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001537
1538>>> def f(): (yield bar) = y
1539Traceback (most recent call last):
1540 ...
Guido van Rossum33d26892007-08-05 15:29:28 +00001541SyntaxError: can't assign to yield expression
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001542
1543>>> def f(): (yield bar) += y
1544Traceback (most recent call last):
1545 ...
Benjamin Peterson87c8d872009-06-11 22:54:11 +00001546SyntaxError: can't assign to yield expression
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001547
1548
1549Now check some throw() conditions:
1550
1551>>> def f():
1552... while True:
1553... try:
Guido van Rossum7131f842007-02-09 20:13:25 +00001554... print((yield))
Guido van Rossumb940e112007-01-10 16:19:56 +00001555... except ValueError as v:
Guido van Rossumc420b2f2007-02-09 22:09:01 +00001556... print("caught ValueError (%s)" % (v))
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001557>>> import sys
1558>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001559>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001560
1561>>> g.throw(ValueError) # type only
1562caught ValueError ()
1563
1564>>> g.throw(ValueError("xyz")) # value only
1565caught ValueError (xyz)
1566
1567>>> g.throw(ValueError, ValueError(1)) # value+matching type
1568caught ValueError (1)
1569
1570>>> g.throw(ValueError, TypeError(1)) # mismatched type, rewrapped
1571caught ValueError (1)
1572
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001573>>> g.throw(ValueError, ValueError(1), None) # explicit None traceback
1574caught ValueError (1)
1575
Tim Peterse9fe7e02005-08-07 03:04:58 +00001576>>> g.throw(ValueError(1), "foo") # bad args
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001577Traceback (most recent call last):
1578 ...
1579TypeError: instance exception may not have a separate value
1580
Tim Peterse9fe7e02005-08-07 03:04:58 +00001581>>> g.throw(ValueError, "foo", 23) # bad args
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001582Traceback (most recent call last):
1583 ...
1584TypeError: throw() third argument must be a traceback object
1585
Guido van Rossumbf12cdb2006-08-17 20:24:18 +00001586>>> g.throw("abc")
1587Traceback (most recent call last):
1588 ...
1589TypeError: exceptions must be classes or instances deriving from BaseException, not str
1590
1591>>> g.throw(0)
1592Traceback (most recent call last):
1593 ...
1594TypeError: exceptions must be classes or instances deriving from BaseException, not int
1595
1596>>> g.throw(list)
1597Traceback (most recent call last):
1598 ...
1599TypeError: exceptions must be classes or instances deriving from BaseException, not type
1600
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001601>>> def throw(g,exc):
1602... try:
1603... raise exc
1604... except:
1605... g.throw(*sys.exc_info())
Tim Peterse9fe7e02005-08-07 03:04:58 +00001606>>> throw(g,ValueError) # do it with traceback included
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001607caught ValueError ()
1608
1609>>> g.send(1)
16101
1611
Tim Peterse9fe7e02005-08-07 03:04:58 +00001612>>> throw(g,TypeError) # terminate the generator
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001613Traceback (most recent call last):
1614 ...
1615TypeError
1616
Guido van Rossum7131f842007-02-09 20:13:25 +00001617>>> print(g.gi_frame)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001618None
1619
1620>>> g.send(2)
1621Traceback (most recent call last):
1622 ...
1623StopIteration
1624
Tim Peterse9fe7e02005-08-07 03:04:58 +00001625>>> g.throw(ValueError,6) # throw on closed generator
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001626Traceback (most recent call last):
1627 ...
1628ValueError: 6
1629
Tim Peterse9fe7e02005-08-07 03:04:58 +00001630>>> f().throw(ValueError,7) # throw on just-opened generator
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001631Traceback (most recent call last):
1632 ...
1633ValueError: 7
1634
Antoine Pitrou551ba202011-10-18 16:40:50 +02001635Plain "raise" inside a generator should preserve the traceback (#13188).
1636The traceback should have 3 levels:
1637- g.throw()
1638- f()
1639- 1/0
1640
1641>>> def f():
1642... try:
1643... yield
1644... except:
1645... raise
1646>>> g = f()
1647>>> try:
1648... 1/0
1649... except ZeroDivisionError as v:
1650... try:
1651... g.throw(v)
1652... except Exception as w:
1653... tb = w.__traceback__
1654>>> levels = 0
1655>>> while tb:
1656... levels += 1
1657... tb = tb.tb_next
1658>>> levels
16593
1660
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001661Now let's try closing a generator:
1662
1663>>> def f():
1664... try: yield
1665... except GeneratorExit:
Guido van Rossum7131f842007-02-09 20:13:25 +00001666... print("exiting")
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001667
1668>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001669>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001670>>> g.close()
1671exiting
1672>>> g.close() # should be no-op now
1673
1674>>> f().close() # close on just-opened generator should be fine
1675
Tim Peterse9fe7e02005-08-07 03:04:58 +00001676>>> def f(): yield # an even simpler generator
1677>>> f().close() # close before opening
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001678>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001679>>> next(g)
Tim Peterse9fe7e02005-08-07 03:04:58 +00001680>>> g.close() # close normally
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001681
1682And finalization:
1683
1684>>> def f():
1685... try: yield
1686... finally:
Guido van Rossum7131f842007-02-09 20:13:25 +00001687... print("exiting")
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001688
1689>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001690>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001691>>> del g
1692exiting
1693
1694
Christian Heimescbf3b5c2007-12-03 21:02:03 +00001695GeneratorExit is not caught by except Exception:
1696
1697>>> def f():
1698... try: yield
1699... except Exception:
1700... print('except')
1701... finally:
1702... print('finally')
1703
1704>>> g = f()
1705>>> next(g)
1706>>> del g
1707finally
1708
1709
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001710Now let's try some ill-behaved generators:
1711
1712>>> def f():
1713... try: yield
1714... except GeneratorExit:
1715... yield "foo!"
1716>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001717>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001718>>> g.close()
1719Traceback (most recent call last):
1720 ...
1721RuntimeError: generator ignored GeneratorExit
1722>>> g.close()
1723
1724
1725Our ill-behaved code should be invoked during GC:
1726
Guido van Rossum34d19282007-08-09 01:03:29 +00001727>>> import sys, io
1728>>> old, sys.stderr = sys.stderr, io.StringIO()
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001729>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001730>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001731>>> del g
1732>>> sys.stderr.getvalue().startswith(
Neal Norwitz2633c692007-02-26 22:22:47 +00001733... "Exception RuntimeError: 'generator ignored GeneratorExit' in "
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001734... )
1735True
1736>>> sys.stderr = old
1737
1738
1739And errors thrown during closing should propagate:
1740
1741>>> def f():
1742... try: yield
1743... except GeneratorExit:
1744... raise TypeError("fie!")
1745>>> g = f()
Georg Brandla18af4e2007-04-21 15:47:16 +00001746>>> next(g)
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001747>>> g.close()
1748Traceback (most recent call last):
1749 ...
1750TypeError: fie!
1751
1752
1753Ensure that various yield expression constructs make their
1754enclosing function a generator:
1755
1756>>> def f(): x += yield
1757>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +00001758<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001759
1760>>> def f(): x = yield
1761>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +00001762<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001763
1764>>> def f(): lambda x=(yield): 1
1765>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +00001766<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001767
1768>>> def f(): x=(i for i in (yield) if (yield))
1769>>> type(f())
Martin v. Löwis250ad612008-04-07 05:43:42 +00001770<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001771
1772>>> def f(d): d[(yield "a")] = d[(yield "b")] = 27
1773>>> data = [1,2]
1774>>> g = f(data)
1775>>> type(g)
Martin v. Löwis250ad612008-04-07 05:43:42 +00001776<class 'generator'>
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001777>>> g.send(None)
1778'a'
1779>>> data
1780[1, 2]
1781>>> g.send(0)
1782'b'
1783>>> data
1784[27, 2]
1785>>> try: g.send(1)
1786... except StopIteration: pass
1787>>> data
1788[27, 27]
1789
1790"""
1791
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001792refleaks_tests = """
1793Prior to adding cycle-GC support to itertools.tee, this code would leak
1794references. We add it to the standard suite so the routine refleak-tests
1795would trigger if it starts being uncleanable again.
1796
1797>>> import itertools
1798>>> def leak():
1799... class gen:
1800... def __iter__(self):
1801... return self
Georg Brandla18af4e2007-04-21 15:47:16 +00001802... def __next__(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001803... return self.item
1804... g = gen()
1805... head, tail = itertools.tee(g)
1806... g.item = head
1807... return head
1808>>> it = leak()
1809
1810Make sure to also test the involvement of the tee-internal teedataobject,
1811which stores returned items.
1812
Georg Brandla18af4e2007-04-21 15:47:16 +00001813>>> item = next(it)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001814
1815
1816
1817This test leaked at one point due to generator finalization/destruction.
1818It was copied from Lib/test/leakers/test_generator_cycle.py before the file
1819was removed.
1820
1821>>> def leak():
1822... def gen():
1823... while True:
1824... yield g
1825... g = gen()
1826
1827>>> leak()
1828
1829
1830
1831This test isn't really generator related, but rather exception-in-cleanup
1832related. The coroutine tests (above) just happen to cause an exception in
1833the generator's __del__ (tp_del) method. We can also test for this
1834explicitly, without generators. We do have to redirect stderr to avoid
1835printing warnings and to doublecheck that we actually tested what we wanted
1836to test.
1837
Guido van Rossum34d19282007-08-09 01:03:29 +00001838>>> import sys, io
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001839>>> old = sys.stderr
1840>>> try:
Guido van Rossum34d19282007-08-09 01:03:29 +00001841... sys.stderr = io.StringIO()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001842... class Leaker:
1843... def __del__(self):
1844... raise RuntimeError
1845...
1846... l = Leaker()
1847... del l
1848... err = sys.stderr.getvalue().strip()
1849... err.startswith(
Neal Norwitz2633c692007-02-26 22:22:47 +00001850... "Exception RuntimeError: RuntimeError() in <"
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001851... )
1852... err.endswith("> ignored")
1853... len(err.splitlines())
1854... finally:
1855... sys.stderr = old
1856True
1857True
18581
1859
1860
1861
1862These refleak tests should perhaps be in a testfile of their own,
1863test_generators just happened to be the test that drew these out.
1864
1865"""
1866
Tim Petersf6ed0742001-06-27 07:17:57 +00001867__test__ = {"tut": tutorial_tests,
1868 "pep": pep_tests,
1869 "email": email_tests,
1870 "fun": fun_tests,
Tim Petersbe4f0a72001-06-29 02:41:16 +00001871 "syntax": syntax_tests,
Fred Drake56d12662002-08-09 18:37:10 +00001872 "conjoin": conjoin_tests,
1873 "weakref": weakref_tests,
Phillip J. Eby0d6615f2005-08-02 00:46:46 +00001874 "coroutine": coroutine_tests,
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001875 "refleaks": refleaks_tests,
Fred Drake56d12662002-08-09 18:37:10 +00001876 }
Tim Peters1def3512001-06-23 20:27:04 +00001877
1878# Magic test name that regrtest.py invokes *after* importing this module.
1879# This worms around a bootstrap problem.
1880# Note that doctest and regrtest both look in sys.argv for a "-v" argument,
1881# so this works as expected in both ways of running regrtest.
Tim Petersa0a62222001-09-09 06:12:01 +00001882def test_main(verbose=None):
Benjamin Petersonee8712c2008-05-20 21:35:26 +00001883 from test import support, test_generators
1884 support.run_doctest(test_generators, verbose)
Tim Peters1def3512001-06-23 20:27:04 +00001885
1886# This part isn't needed for regrtest, but for running the test directly.
1887if __name__ == "__main__":
Tim Petersa0a62222001-09-09 06:12:01 +00001888 test_main(1)