blob: e0d6cfab1db99f24a904cd8fe92ea97b0700c38b [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
50 ... return
51 ... 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
138Specification: Return
139
140 Note that return isn't always equivalent to raising StopIteration: the
141 difference lies in how enclosing try/except constructs are treated.
142 For example,
143
144 >>> def f1():
145 ... try:
146 ... return
147 ... except:
148 ... yield 1
149 >>> print list(f1())
150 []
151
152 because, as in any function, return simply exits, but
153
154 >>> def f2():
155 ... try:
156 ... raise StopIteration
157 ... except:
158 ... yield 42
159 >>> print list(f2())
160 [42]
161
162 because StopIteration is captured by a bare "except", as is any
163 exception.
164
165Specification: Generators and Exception Propagation
166
167 >>> def f():
168 ... return 1/0
169 >>> def g():
170 ... yield f() # the zero division exception propagates
171 ... yield 42 # and we'll never get here
172 >>> k = g()
173 >>> k.next()
174 Traceback (most recent call last):
175 File "<stdin>", line 1, in ?
176 File "<stdin>", line 2, in g
177 File "<stdin>", line 2, in f
178 ZeroDivisionError: integer division or modulo by zero
179 >>> k.next() # and the generator cannot be resumed
180 Traceback (most recent call last):
181 File "<stdin>", line 1, in ?
182 StopIteration
183 >>>
184
185Specification: Try/Except/Finally
186
187 >>> def f():
188 ... try:
189 ... yield 1
190 ... try:
191 ... yield 2
192 ... 1/0
193 ... yield 3 # never get here
194 ... except ZeroDivisionError:
195 ... yield 4
196 ... yield 5
197 ... raise
198 ... except:
199 ... yield 6
200 ... yield 7 # the "raise" above stops this
201 ... except:
202 ... yield 8
203 ... yield 9
204 ... try:
205 ... x = 12
206 ... finally:
207 ... yield 10
208 ... yield 11
209 >>> print list(f())
210 [1, 2, 4, 5, 8, 9, 10, 11]
211 >>>
212
Tim Peters6ba5f792001-06-23 20:45:43 +0000213Guido's binary tree example.
214
215 >>> # A binary tree class.
216 >>> class Tree:
217 ...
218 ... def __init__(self, label, left=None, right=None):
219 ... self.label = label
220 ... self.left = left
221 ... self.right = right
222 ...
223 ... def __repr__(self, level=0, indent=" "):
224 ... s = level*indent + `self.label`
225 ... if self.left:
226 ... s = s + "\\n" + self.left.__repr__(level+1, indent)
227 ... if self.right:
228 ... s = s + "\\n" + self.right.__repr__(level+1, indent)
229 ... return s
230 ...
231 ... def __iter__(self):
232 ... return inorder(self)
233
234 >>> # Create a Tree from a list.
235 >>> def tree(list):
236 ... n = len(list)
237 ... if n == 0:
238 ... return []
239 ... i = n / 2
240 ... return Tree(list[i], tree(list[:i]), tree(list[i+1:]))
241
242 >>> # Show it off: create a tree.
243 >>> t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
244
245 >>> # A recursive generator that generates Tree leaves in in-order.
246 >>> def inorder(t):
247 ... if t:
248 ... for x in inorder(t.left):
249 ... yield x
250 ... yield t.label
251 ... for x in inorder(t.right):
252 ... yield x
253
254 >>> # Show it off: create a tree.
255 ... t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
256 ... # Print the nodes of the tree in in-order.
257 ... for x in t:
258 ... print x,
259 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
260
261 >>> # A non-recursive generator.
262 >>> def inorder(node):
263 ... stack = []
264 ... while node:
265 ... while node.left:
266 ... stack.append(node)
267 ... node = node.left
268 ... yield node.label
269 ... while not node.right:
270 ... try:
271 ... node = stack.pop()
272 ... except IndexError:
273 ... return
274 ... yield node.label
275 ... node = node.right
276
277 >>> # Exercise the non-recursive generator.
278 >>> for x in t:
279 ... print x,
280 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
281
282"""
283
Tim Petersb2bc6a92001-06-24 10:14:27 +0000284# Examples from Iterator-List and Python-Dev and c.l.py.
Tim Peters6ba5f792001-06-23 20:45:43 +0000285
286email_tests = """
287
288The difference between yielding None and returning it.
289
290>>> def g():
291... for i in range(3):
292... yield None
293... yield None
294... return
295>>> list(g())
296[None, None, None, None]
297
298Ensure that explicitly raising StopIteration acts like any other exception
299in try/except, not like a return.
300
301>>> def g():
302... yield 1
303... try:
304... raise StopIteration
305... except:
306... yield 2
307... yield 3
308>>> list(g())
309[1, 2, 3]
Tim Petersb9e9ff12001-06-24 03:44:52 +0000310
311A generator can't be resumed while it's already running.
312
313>>> def g():
314... i = me.next()
315... yield i
316>>> me = g()
317>>> me.next()
318Traceback (most recent call last):
319 ...
320 File "<string>", line 2, in g
321ValueError: generator already executing
Tim Petersb2bc6a92001-06-24 10:14:27 +0000322
323Next one was posted to c.l.py.
324
325>>> def gcomb(x, k):
326... "Generate all combinations of k elements from list x."
327...
328... if k > len(x):
329... return
330... if k == 0:
331... yield []
332... else:
333... first, rest = x[0], x[1:]
334... # A combination does or doesn't contain first.
335... # If it does, the remainder is a k-1 comb of rest.
336... for c in gcomb(rest, k-1):
337... c.insert(0, first)
338... yield c
339... # If it doesn't contain first, it's a k comb of rest.
340... for c in gcomb(rest, k):
341... yield c
342
343>>> seq = range(1, 5)
344>>> for k in range(len(seq) + 2):
345... print "%d-combs of %s:" % (k, seq)
346... for c in gcomb(seq, k):
347... print " ", c
3480-combs of [1, 2, 3, 4]:
349 []
3501-combs of [1, 2, 3, 4]:
351 [1]
352 [2]
353 [3]
354 [4]
3552-combs of [1, 2, 3, 4]:
356 [1, 2]
357 [1, 3]
358 [1, 4]
359 [2, 3]
360 [2, 4]
361 [3, 4]
3623-combs of [1, 2, 3, 4]:
363 [1, 2, 3]
364 [1, 2, 4]
365 [1, 3, 4]
366 [2, 3, 4]
3674-combs of [1, 2, 3, 4]:
368 [1, 2, 3, 4]
3695-combs of [1, 2, 3, 4]:
Tim Peters6ba5f792001-06-23 20:45:43 +0000370"""
371
Tim Peters0f9da0a2001-06-23 21:01:47 +0000372# Fun tests (for sufficiently warped notions of "fun").
373
374fun_tests = """
375
376Build up to a recursive Sieve of Eratosthenes generator.
377
378>>> def firstn(g, n):
379... return [g.next() for i in range(n)]
380
381>>> def intsfrom(i):
382... while 1:
383... yield i
384... i += 1
385
386>>> firstn(intsfrom(5), 7)
387[5, 6, 7, 8, 9, 10, 11]
388
389>>> def exclude_multiples(n, ints):
390... for i in ints:
391... if i % n:
392... yield i
393
394>>> firstn(exclude_multiples(3, intsfrom(1)), 6)
395[1, 2, 4, 5, 7, 8]
396
397>>> def sieve(ints):
398... prime = ints.next()
399... yield prime
400... not_divisible_by_prime = exclude_multiples(prime, ints)
401... for p in sieve(not_divisible_by_prime):
402... yield p
403
404>>> primes = sieve(intsfrom(2))
405>>> firstn(primes, 20)
406[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 +0000407
408Another famous problem: generate all integers of the form
409 2**i * 3**j * 5**k
410in increasing order, where i,j,k >= 0. Trickier than it may look at first!
411Try writing it without generators, and correctly, and without generating
4123 internal results for each result output.
413
414>>> def times(n, g):
415... for i in g:
416... yield n * i
417>>> firstn(times(10, intsfrom(1)), 10)
418[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
419
420>>> def merge(g, h):
421... ng = g.next()
422... nh = h.next()
423... while 1:
424... if ng < nh:
425... yield ng
426... ng = g.next()
427... elif ng > nh:
428... yield nh
429... nh = h.next()
430... else:
431... yield ng
432... ng = g.next()
433... nh = h.next()
434
435This works, but is doing a whale of a lot or redundant work -- it's not
436clear how to get the internal uses of m235 to share a single generator.
437Note that me_times2 (etc) each need to see every element in the result
438sequence. So this is an example where lazy lists are more natural (you
439can look at the head of a lazy list any number of times).
440
441>>> def m235():
442... yield 1
443... me_times2 = times(2, m235())
444... me_times3 = times(3, m235())
445... me_times5 = times(5, m235())
446... for i in merge(merge(me_times2,
447... me_times3),
448... me_times5):
449... yield i
450
451>>> result = m235()
452>>> for i in range(5):
453... print firstn(result, 15)
454[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
455[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
456[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
457[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
458[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Tim Petersee309272001-06-24 05:47:06 +0000459
460Heh. Here's one way to get a shared list, complete with an excruciating
461namespace renaming trick. The *pretty* part is that the times() and merge()
462functions can be reused as-is, because they only assume their stream
463arguments are iterable -- a LazyList is the same as a generator to times().
464
465>>> class LazyList:
466... def __init__(self, g):
467... self.sofar = []
468... self.fetch = g.next
469...
470... def __getitem__(self, i):
471... sofar, fetch = self.sofar, self.fetch
472... while i >= len(sofar):
473... sofar.append(fetch())
474... return sofar[i]
475
476>>> def m235():
477... yield 1
Tim Petersea2e97a2001-06-24 07:10:02 +0000478... # Gack: m235 below actually refers to a LazyList.
Tim Petersee309272001-06-24 05:47:06 +0000479... me_times2 = times(2, m235)
480... me_times3 = times(3, m235)
481... me_times5 = times(5, m235)
482... for i in merge(merge(me_times2,
483... me_times3),
484... me_times5):
485... yield i
486
487>>> m235 = LazyList(m235())
488>>> for i in range(5):
489... print [m235[j] for j in range(15*i, 15*(i+1))]
490[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
491[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
492[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
493[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
494[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Tim Peters0f9da0a2001-06-23 21:01:47 +0000495"""
496
Tim Petersea2e97a2001-06-24 07:10:02 +0000497# syntax_tests mostly provokes SyntaxErrors.
Tim Petersee309272001-06-24 05:47:06 +0000498
Tim Petersea2e97a2001-06-24 07:10:02 +0000499syntax_tests = """
500
501>>> def f():
502... return 22
503... yield 1
504Traceback (most recent call last):
505 ...
506SyntaxError: 'return' with argument inside generator (<string>, line 2)
507
508>>> def f():
509... yield 1
510... return 22
511Traceback (most recent call last):
512 ...
513SyntaxError: 'return' with argument inside generator (<string>, line 3)
514
515"return None" is not the same as "return" in a generator:
516
517>>> def f():
518... yield 1
519... return None
520Traceback (most recent call last):
521 ...
522SyntaxError: 'return' with argument inside generator (<string>, line 3)
523
524This one is fine:
525
526>>> def f():
527... yield 1
528... return
529
530>>> def f():
531... try:
532... yield 1
533... finally:
534... pass
535Traceback (most recent call last):
536 ...
537SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<string>, line 3)
538
539>>> def f():
540... try:
541... try:
542... 1/0
543... except ZeroDivisionError:
544... yield 666 # bad because *outer* try has finally
545... except:
546... pass
547... finally:
548... pass
549Traceback (most recent call last):
550 ...
551SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<string>, line 6)
552
553But this is fine:
554
555>>> def f():
556... try:
557... try:
558... yield 12
559... 1/0
560... except ZeroDivisionError:
561... yield 666
562... except:
563... try:
564... x = 12
565... finally:
566... yield 12
567... except:
568... return
569>>> list(f())
570[12, 666]
571"""
572
573__test__ = {"tut": tutorial_tests,
574 "pep": pep_tests,
575 "email": email_tests,
576 "fun": fun_tests,
577 "syntax": syntax_tests}
Tim Peters1def3512001-06-23 20:27:04 +0000578
579# Magic test name that regrtest.py invokes *after* importing this module.
580# This worms around a bootstrap problem.
581# Note that doctest and regrtest both look in sys.argv for a "-v" argument,
582# so this works as expected in both ways of running regrtest.
583def test_main():
584 import doctest, test_generators
Tim Peters2106ef02001-06-25 01:30:12 +0000585 if 0:
586 # Temporary block to help track down leaks. So far, the blame
587 # has fallen mostly on doctest.
588 for i in range(1000):
589 doctest.master = None
590 doctest.testmod(test_generators)
591 else:
592 doctest.testmod(test_generators)
Tim Peters1def3512001-06-23 20:27:04 +0000593
594# This part isn't needed for regrtest, but for running the test directly.
595if __name__ == "__main__":
596 test_main()