blob: 86898bb9f11582f3463a3be263408fd24436445d [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 Peters3e7b1a02001-06-25 19:46:25 +0000370
Tim Peterse77f2e22001-06-26 22:24:51 +0000371From the Iterators list, about the types of these things.
Tim Peters3e7b1a02001-06-25 19:46:25 +0000372
373>>> def g():
374... yield 1
375...
376>>> type(g)
377<type 'function'>
378>>> i = g()
379>>> type(i)
380<type 'generator'>
381>>> dir(i)
Tim Peterse77f2e22001-06-26 22:24:51 +0000382['gi_frame', 'gi_running', 'next']
Tim Peters3e7b1a02001-06-25 19:46:25 +0000383>>> print i.next.__doc__
384next() -- get the next value, or raise StopIteration
385>>> iter(i) is i
3861
387>>> import types
388>>> isinstance(i, types.GeneratorType)
3891
Tim Peterse77f2e22001-06-26 22:24:51 +0000390
391And more, added later.
392
393>>> i.gi_running
3940
395>>> type(i.gi_frame)
396<type 'frame'>
397>>> i.gi_running = 42
398Traceback (most recent call last):
399 ...
400TypeError: object has read-only attributes
401>>> def g():
402... yield me.gi_running
403>>> me = g()
404>>> me.gi_running
4050
406>>> me.next()
4071
408>>> me.gi_running
4090
Tim Peters6ba5f792001-06-23 20:45:43 +0000410"""
411
Tim Peters0f9da0a2001-06-23 21:01:47 +0000412# Fun tests (for sufficiently warped notions of "fun").
413
414fun_tests = """
415
416Build up to a recursive Sieve of Eratosthenes generator.
417
418>>> def firstn(g, n):
419... return [g.next() for i in range(n)]
420
421>>> def intsfrom(i):
422... while 1:
423... yield i
424... i += 1
425
426>>> firstn(intsfrom(5), 7)
427[5, 6, 7, 8, 9, 10, 11]
428
429>>> def exclude_multiples(n, ints):
430... for i in ints:
431... if i % n:
432... yield i
433
434>>> firstn(exclude_multiples(3, intsfrom(1)), 6)
435[1, 2, 4, 5, 7, 8]
436
437>>> def sieve(ints):
438... prime = ints.next()
439... yield prime
440... not_divisible_by_prime = exclude_multiples(prime, ints)
441... for p in sieve(not_divisible_by_prime):
442... yield p
443
444>>> primes = sieve(intsfrom(2))
445>>> firstn(primes, 20)
446[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 +0000447
448Another famous problem: generate all integers of the form
449 2**i * 3**j * 5**k
450in increasing order, where i,j,k >= 0. Trickier than it may look at first!
451Try writing it without generators, and correctly, and without generating
4523 internal results for each result output.
453
Tim Petersb6c3cea2001-06-26 03:36:28 +0000454XXX Suspect there's memory leaks in this one; definitely in the next
455XXX version.
456
Tim Petersb9e9ff12001-06-24 03:44:52 +0000457>>> def times(n, g):
458... for i in g:
459... yield n * i
460>>> firstn(times(10, intsfrom(1)), 10)
461[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
462
463>>> def merge(g, h):
464... ng = g.next()
465... nh = h.next()
466... while 1:
467... if ng < nh:
468... yield ng
469... ng = g.next()
470... elif ng > nh:
471... yield nh
472... nh = h.next()
473... else:
474... yield ng
475... ng = g.next()
476... nh = h.next()
477
478This works, but is doing a whale of a lot or redundant work -- it's not
479clear how to get the internal uses of m235 to share a single generator.
480Note that me_times2 (etc) each need to see every element in the result
481sequence. So this is an example where lazy lists are more natural (you
482can look at the head of a lazy list any number of times).
483
484>>> def m235():
485... yield 1
486... me_times2 = times(2, m235())
487... me_times3 = times(3, m235())
488... me_times5 = times(5, m235())
489... for i in merge(merge(me_times2,
490... me_times3),
491... me_times5):
492... yield i
493
494>>> result = m235()
495>>> for i in range(5):
496... print firstn(result, 15)
497[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
498[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
499[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
500[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
501[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Tim Petersee309272001-06-24 05:47:06 +0000502
503Heh. Here's one way to get a shared list, complete with an excruciating
504namespace renaming trick. The *pretty* part is that the times() and merge()
505functions can be reused as-is, because they only assume their stream
506arguments are iterable -- a LazyList is the same as a generator to times().
507
Tim Petersb6c3cea2001-06-26 03:36:28 +0000508XXX Massive memory leaks in this; see Python-Iterators.
509
Tim Petersee309272001-06-24 05:47:06 +0000510>>> class LazyList:
511... def __init__(self, g):
512... self.sofar = []
513... self.fetch = g.next
514...
515... def __getitem__(self, i):
516... sofar, fetch = self.sofar, self.fetch
517... while i >= len(sofar):
518... sofar.append(fetch())
519... return sofar[i]
520
521>>> def m235():
522... yield 1
Tim Petersea2e97a2001-06-24 07:10:02 +0000523... # Gack: m235 below actually refers to a LazyList.
Tim Petersee309272001-06-24 05:47:06 +0000524... me_times2 = times(2, m235)
525... me_times3 = times(3, m235)
526... me_times5 = times(5, m235)
527... for i in merge(merge(me_times2,
528... me_times3),
529... me_times5):
530... yield i
531
532>>> m235 = LazyList(m235())
533>>> for i in range(5):
534... print [m235[j] for j in range(15*i, 15*(i+1))]
535[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
536[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
537[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
538[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
539[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
Tim Peters0f9da0a2001-06-23 21:01:47 +0000540"""
541
Tim Petersb6c3cea2001-06-26 03:36:28 +0000542# syntax_tests mostly provokes SyntaxErrors. Also fiddling with #if 0
543# hackery.
Tim Petersee309272001-06-24 05:47:06 +0000544
Tim Petersea2e97a2001-06-24 07:10:02 +0000545syntax_tests = """
546
547>>> def f():
548... return 22
549... yield 1
550Traceback (most recent call last):
551 ...
552SyntaxError: 'return' with argument inside generator (<string>, line 2)
553
554>>> def f():
555... yield 1
556... return 22
557Traceback (most recent call last):
558 ...
559SyntaxError: 'return' with argument inside generator (<string>, line 3)
560
561"return None" is not the same as "return" in a generator:
562
563>>> def f():
564... yield 1
565... return None
566Traceback (most recent call last):
567 ...
568SyntaxError: 'return' with argument inside generator (<string>, line 3)
569
570This one is fine:
571
572>>> def f():
573... yield 1
574... return
575
576>>> def f():
577... try:
578... yield 1
579... finally:
580... pass
581Traceback (most recent call last):
582 ...
583SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<string>, line 3)
584
585>>> def f():
586... try:
587... try:
588... 1/0
589... except ZeroDivisionError:
590... yield 666 # bad because *outer* try has finally
591... except:
592... pass
593... finally:
594... pass
595Traceback (most recent call last):
596 ...
597SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<string>, line 6)
598
599But this is fine:
600
601>>> def f():
602... try:
603... try:
604... yield 12
605... 1/0
606... except ZeroDivisionError:
607... yield 666
608... except:
609... try:
610... x = 12
611... finally:
612... yield 12
613... except:
614... return
615>>> list(f())
616[12, 666]
Tim Petersb6c3cea2001-06-26 03:36:28 +0000617
618>>> def f():
619... if 0:
620... yield 1
621>>> type(f())
622<type 'generator'>
623
624>>> def f():
625... if "":
626... yield None
627>>> type(f())
628<type 'generator'>
629
630>>> def f():
631... return
632... try:
633... if x==4:
634... pass
635... elif 0:
636... try:
637... 1/0
638... except SyntaxError:
639... pass
640... else:
641... if 0:
642... while 12:
643... x += 1
644... yield 2 # don't blink
645... f(a, b, c, d, e)
646... else:
647... pass
648... except:
649... x = 1
650... return
651>>> type(f())
652<type 'generator'>
653
654>>> def f():
655... if 0:
656... def g():
657... yield 1
658...
659>>> type(f())
660<type 'None'>
661
662>>> def f():
663... if 0:
664... class C:
665... def __init__(self):
666... yield 1
667... def f(self):
668... yield 2
669>>> type(f())
670<type 'None'>
Tim Petersea2e97a2001-06-24 07:10:02 +0000671"""
672
Tim Petersb6c3cea2001-06-26 03:36:28 +0000673
674x_tests = """
675
676>>> def firstn(g, n):
677... return [g.next() for i in range(n)]
678
679>>> def times(n, g):
680... for i in g:
681... yield n * i
682
683>>> def merge(g, h):
684... ng = g.next()
685... nh = h.next()
686... while 1:
687... if ng < nh:
688... yield ng
689... ng = g.next()
690... elif ng > nh:
691... yield nh
692... nh = h.next()
693... else:
694... yield ng
695... ng = g.next()
696... nh = h.next()
697
698>>> class LazyList:
699... def __init__(self, g):
700... self.sofar = []
701... self.fetch = g.next
702...
703... def __getitem__(self, i):
704... sofar, fetch = self.sofar, self.fetch
705... while i >= len(sofar):
706... sofar.append(fetch())
707... return sofar[i]
708
709>>> def m235():
710... yield 1
711... # Gack: m235 below actually refers to a LazyList.
712... me_times2 = times(2, m235)
713... me_times3 = times(3, m235)
714... me_times5 = times(5, m235)
715... for i in merge(merge(me_times2,
716... me_times3),
717... me_times5):
718... yield i
719
720>>> m235 = LazyList(m235())
721>>> for i in range(5):
722... x = [m235[j] for j in range(15*i, 15*(i+1))]
723
724
725[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24]
726[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80]
727[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192]
728[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384]
729[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675]
730"""
731
732__test__ = {"tut": tutorial_tests, # clean
733 "pep": pep_tests, # clean
734 "email": email_tests, # clean
735 "fun": fun_tests, # leaks
736 "syntax": syntax_tests # clean
737 #"x": x_tests
738}
Tim Peters1def3512001-06-23 20:27:04 +0000739
740# Magic test name that regrtest.py invokes *after* importing this module.
741# This worms around a bootstrap problem.
742# Note that doctest and regrtest both look in sys.argv for a "-v" argument,
743# so this works as expected in both ways of running regrtest.
744def test_main():
745 import doctest, test_generators
Tim Peters2106ef02001-06-25 01:30:12 +0000746 if 0:
747 # Temporary block to help track down leaks. So far, the blame
748 # has fallen mostly on doctest.
Tim Petersb6c3cea2001-06-26 03:36:28 +0000749 for i in range(5000):
Tim Peters2106ef02001-06-25 01:30:12 +0000750 doctest.master = None
751 doctest.testmod(test_generators)
752 else:
753 doctest.testmod(test_generators)
Tim Peters1def3512001-06-23 20:27:04 +0000754
755# This part isn't needed for regrtest, but for running the test directly.
756if __name__ == "__main__":
757 test_main()