|
| 1 | +simple_tests = """ |
| 2 | +Let's try a simple generator: |
| 3 | +
|
| 4 | + >>> def f(): |
| 5 | + ... yield 1 |
| 6 | + ... yield 2 |
| 7 | +
|
| 8 | + >>> g = f() |
| 9 | + >>> g.next() |
| 10 | + 1 |
| 11 | + >>> g.next() |
| 12 | + 2 |
| 13 | + >>> g.next() |
| 14 | + Traceback (most recent call last): |
| 15 | + File "<stdin>", line 1, in ? |
| 16 | + File "<stdin>", line 2, in g |
| 17 | + StopIteration |
| 18 | +
|
| 19 | +"return" stops the generator: |
| 20 | +
|
| 21 | + >>> def f(): |
| 22 | + ... yield 1 |
| 23 | + ... return |
| 24 | + ... yield 2 # never reached |
| 25 | + ... |
| 26 | + >>> g = f() |
| 27 | + >>> g.next() |
| 28 | + 1 |
| 29 | + >>> g.next() |
| 30 | + Traceback (most recent call last): |
| 31 | + File "<stdin>", line 1, in ? |
| 32 | + File "<stdin>", line 3, in f |
| 33 | + StopIteration |
| 34 | + >>> g.next() # once stopped, can't be resumed |
| 35 | + Traceback (most recent call last): |
| 36 | + File "<stdin>", line 1, in ? |
| 37 | + StopIteration |
| 38 | +
|
| 39 | +"raise StopIteration" stops the generator too: |
| 40 | +
|
| 41 | + >>> def f(): |
| 42 | + ... yield 1 |
| 43 | + ... return |
| 44 | + ... yield 2 # never reached |
| 45 | + ... |
| 46 | + >>> g = f() |
| 47 | + >>> g.next() |
| 48 | + 1 |
| 49 | + >>> g.next() |
| 50 | + Traceback (most recent call last): |
| 51 | + File "<stdin>", line 1, in ? |
| 52 | + StopIteration |
| 53 | + >>> g.next() |
| 54 | + Traceback (most recent call last): |
| 55 | + File "<stdin>", line 1, in ? |
| 56 | + StopIteration |
| 57 | +
|
| 58 | +However, they are not exactly equivalent: |
| 59 | +
|
| 60 | + >>> def g1(): |
| 61 | + ... try: |
| 62 | + ... return |
| 63 | + ... except: |
| 64 | + ... yield 1 |
| 65 | + ... |
| 66 | + >>> list(g1()) |
| 67 | + [] |
| 68 | +
|
| 69 | + >>> def g2(): |
| 70 | + ... try: |
| 71 | + ... raise StopIteration |
| 72 | + ... except: |
| 73 | + ... yield 42 |
| 74 | + >>> print list(g2()) |
| 75 | + [42] |
| 76 | +
|
| 77 | +This may be surprising at first: |
| 78 | +
|
| 79 | + >>> def g3(): |
| 80 | + ... try: |
| 81 | + ... return |
| 82 | + ... finally: |
| 83 | + ... yield 1 |
| 84 | + ... |
| 85 | + >>> list(g3()) |
| 86 | + [1] |
| 87 | +
|
| 88 | +Let's create an alternate range() function implemented as a generator: |
| 89 | +
|
| 90 | + >>> def yrange(n): |
| 91 | + ... for i in range(n): |
| 92 | + ... yield i |
| 93 | + ... |
| 94 | + >>> list(yrange(5)) |
| 95 | + [0, 1, 2, 3, 4] |
| 96 | +
|
| 97 | +Generators always return to the most recent caller: |
| 98 | +
|
| 99 | + >>> def creator(): |
| 100 | + ... r = yrange(5) |
| 101 | + ... print "creator", r.next() |
| 102 | + ... return r |
| 103 | + ... |
| 104 | + >>> def caller(): |
| 105 | + ... r = creator() |
| 106 | + ... for i in r: |
| 107 | + ... print "caller", i |
| 108 | + ... |
| 109 | + >>> caller() |
| 110 | + creator 0 |
| 111 | + caller 1 |
| 112 | + caller 2 |
| 113 | + caller 3 |
| 114 | + caller 4 |
| 115 | +
|
| 116 | +Generators can call other generators: |
| 117 | +
|
| 118 | + >>> def zrange(n): |
| 119 | + ... for i in yrange(n): |
| 120 | + ... yield i |
| 121 | + ... |
| 122 | + >>> list(zrange(5)) |
| 123 | + [0, 1, 2, 3, 4] |
| 124 | +
|
| 125 | +""" |
| 126 | + |
| 127 | +__test__ = {"simple": simple_tests} |
| 128 | + |
| 129 | +# Magic test name that regrtest.py invokes *after* importing this module. |
| 130 | +# This worms around a bootstrap problem. |
| 131 | +# Note that doctest and regrtest both look in sys.argv for a "-v" argument, |
| 132 | +# so this works as expected in both ways of running regrtest. |
| 133 | +def test_main(): |
| 134 | + import doctest, test_generators |
| 135 | + doctest.testmod(test_generators) |
| 136 | + |
| 137 | +# This part isn't needed for regrtest, but for running the test directly. |
| 138 | +if __name__ == "__main__": |
| 139 | + test_main() |
0 commit comments