Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | doctests = """ |
2 | ||
3 | Test simple loop with conditional | |
4 | ||
5 | >>> sum(i*i for i in range(100) if i&1 == 1) | |
6 | 166650 | |
7 | ||
8 | Test simple nesting | |
9 | ||
10 | >>> list((i,j) for i in range(3) for j in range(4) ) | |
11 | [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] | |
12 | ||
13 | Test nesting with the inner expression dependent on the outer | |
14 | ||
15 | >>> list((i,j) for i in range(4) for j in range(i) ) | |
16 | [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] | |
17 | ||
18 | Make sure the induction variable is not exposed | |
19 | ||
20 | >>> i = 20 | |
21 | >>> sum(i*i for i in range(100)) | |
22 | 328350 | |
23 | >>> i | |
24 | 20 | |
25 | ||
26 | Test first class | |
27 | ||
28 | >>> g = (i*i for i in range(4)) | |
29 | >>> type(g) | |
30 | <type 'generator'> | |
31 | >>> list(g) | |
32 | [0, 1, 4, 9] | |
33 | ||
34 | Test direct calls to next() | |
35 | ||
36 | >>> g = (i*i for i in range(3)) | |
37 | >>> g.next() | |
38 | 0 | |
39 | >>> g.next() | |
40 | 1 | |
41 | >>> g.next() | |
42 | 4 | |
43 | >>> g.next() | |
44 | Traceback (most recent call last): | |
45 | File "<pyshell#21>", line 1, in -toplevel- | |
46 | g.next() | |
47 | StopIteration | |
48 | ||
49 | Does it stay stopped? | |
50 | ||
51 | >>> g.next() | |
52 | Traceback (most recent call last): | |
53 | File "<pyshell#21>", line 1, in -toplevel- | |
54 | g.next() | |
55 | StopIteration | |
56 | >>> list(g) | |
57 | [] | |
58 | ||
59 | Test running gen when defining function is out of scope | |
60 | ||
61 | >>> def f(n): | |
62 | ... return (i*i for i in xrange(n)) | |
63 | >>> list(f(10)) | |
64 | [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] | |
65 | ||
66 | >>> def f(n): | |
67 | ... return ((i,j) for i in xrange(3) for j in xrange(n)) | |
68 | >>> list(f(4)) | |
69 | [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] | |
70 | >>> def f(n): | |
71 | ... return ((i,j) for i in xrange(3) for j in xrange(4) if j in xrange(n)) | |
72 | >>> list(f(4)) | |
73 | [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] | |
74 | >>> list(f(2)) | |
75 | [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)] | |
76 | ||
77 | Verify that parenthesis are required in a statement | |
78 | ||
79 | >>> def f(n): | |
80 | ... return i*i for i in xrange(n) | |
81 | Traceback (most recent call last): | |
82 | ... | |
83 | SyntaxError: invalid syntax | |
84 | ||
85 | Verify early binding for the outermost for-expression | |
86 | ||
87 | >>> x=10 | |
88 | >>> g = (i*i for i in range(x)) | |
89 | >>> x = 5 | |
90 | >>> list(g) | |
91 | [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] | |
92 | ||
93 | Verify that the outermost for-expression makes an immediate check | |
94 | for iterability | |
95 | ||
96 | >>> (i for i in 6) | |
97 | Traceback (most recent call last): | |
98 | File "<pyshell#4>", line 1, in -toplevel- | |
99 | (i for i in 6) | |
100 | TypeError: iteration over non-sequence | |
101 | ||
102 | Verify late binding for the outermost if-expression | |
103 | ||
104 | >>> include = (2,4,6,8) | |
105 | >>> g = (i*i for i in range(10) if i in include) | |
106 | >>> include = (1,3,5,7,9) | |
107 | >>> list(g) | |
108 | [1, 9, 25, 49, 81] | |
109 | ||
110 | Verify late binding for the innermost for-expression | |
111 | ||
112 | >>> g = ((i,j) for i in range(3) for j in range(x)) | |
113 | >>> x = 4 | |
114 | >>> list(g) | |
115 | [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] | |
116 | ||
117 | Verify re-use of tuples (a side benefit of using genexps over listcomps) | |
118 | ||
119 | >>> tupleids = map(id, ((i,i) for i in xrange(10))) | |
120 | >>> max(tupleids) - min(tupleids) | |
121 | 0 | |
122 | ||
123 | Verify that syntax error's are raised for genexps used as lvalues | |
124 | ||
125 | >>> (y for y in (1,2)) = 10 | |
126 | Traceback (most recent call last): | |
127 | ... | |
128 | SyntaxError: assign to generator expression not possible | |
129 | ||
130 | >>> (y for y in (1,2)) += 10 | |
131 | Traceback (most recent call last): | |
132 | ... | |
133 | SyntaxError: augmented assign to tuple literal or generator expression not possible | |
134 | ||
135 | ||
136 | ||
137 | ########### Tests borrowed from or inspired by test_generators.py ############ | |
138 | ||
139 | Make a generator that acts like range() | |
140 | ||
141 | >>> yrange = lambda n: (i for i in xrange(n)) | |
142 | >>> list(yrange(10)) | |
143 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
144 | ||
145 | Generators always return to the most recent caller: | |
146 | ||
147 | >>> def creator(): | |
148 | ... r = yrange(5) | |
149 | ... print "creator", r.next() | |
150 | ... return r | |
151 | >>> def caller(): | |
152 | ... r = creator() | |
153 | ... for i in r: | |
154 | ... print "caller", i | |
155 | >>> caller() | |
156 | creator 0 | |
157 | caller 1 | |
158 | caller 2 | |
159 | caller 3 | |
160 | caller 4 | |
161 | ||
162 | Generators can call other generators: | |
163 | ||
164 | >>> def zrange(n): | |
165 | ... for i in yrange(n): | |
166 | ... yield i | |
167 | >>> list(zrange(5)) | |
168 | [0, 1, 2, 3, 4] | |
169 | ||
170 | ||
171 | Verify that a gen exp cannot be resumed while it is actively running: | |
172 | ||
173 | >>> g = (me.next() for i in xrange(10)) | |
174 | >>> me = g | |
175 | >>> me.next() | |
176 | Traceback (most recent call last): | |
177 | File "<pyshell#30>", line 1, in -toplevel- | |
178 | me.next() | |
179 | File "<pyshell#28>", line 1, in <generator expression> | |
180 | g = (me.next() for i in xrange(10)) | |
181 | ValueError: generator already executing | |
182 | ||
183 | Verify exception propagation | |
184 | ||
185 | >>> g = (10 // i for i in (5, 0, 2)) | |
186 | >>> g.next() | |
187 | 2 | |
188 | >>> g.next() | |
189 | Traceback (most recent call last): | |
190 | File "<pyshell#37>", line 1, in -toplevel- | |
191 | g.next() | |
192 | File "<pyshell#35>", line 1, in <generator expression> | |
193 | g = (10 // i for i in (5, 0, 2)) | |
194 | ZeroDivisionError: integer division or modulo by zero | |
195 | >>> g.next() | |
196 | Traceback (most recent call last): | |
197 | File "<pyshell#38>", line 1, in -toplevel- | |
198 | g.next() | |
199 | StopIteration | |
200 | ||
201 | Make sure that None is a valid return value | |
202 | ||
203 | >>> list(None for i in xrange(10)) | |
204 | [None, None, None, None, None, None, None, None, None, None] | |
205 | ||
206 | Check that generator attributes are present | |
207 | ||
208 | >>> g = (i*i for i in range(3)) | |
209 | >>> expected = set(['gi_frame', 'gi_running', 'next']) | |
210 | >>> set(attr for attr in dir(g) if not attr.startswith('__')) >= expected | |
211 | True | |
212 | ||
213 | >>> print g.next.__doc__ | |
214 | x.next() -> the next value, or raise StopIteration | |
215 | >>> import types | |
216 | >>> isinstance(g, types.GeneratorType) | |
217 | True | |
218 | ||
219 | Check the __iter__ slot is defined to return self | |
220 | ||
221 | >>> iter(g) is g | |
222 | True | |
223 | ||
224 | Verify that the running flag is set properly | |
225 | ||
226 | >>> g = (me.gi_running for i in (0,1)) | |
227 | >>> me = g | |
228 | >>> me.gi_running | |
229 | 0 | |
230 | >>> me.next() | |
231 | 1 | |
232 | >>> me.gi_running | |
233 | 0 | |
234 | ||
235 | Verify that genexps are weakly referencable | |
236 | ||
237 | >>> import weakref | |
238 | >>> g = (i*i for i in range(4)) | |
239 | >>> wr = weakref.ref(g) | |
240 | >>> wr() is g | |
241 | True | |
242 | >>> p = weakref.proxy(g) | |
243 | >>> list(p) | |
244 | [0, 1, 4, 9] | |
245 | ||
246 | ||
247 | """ | |
248 | ||
249 | ||
250 | __test__ = {'doctests' : doctests} | |
251 | ||
252 | def test_main(verbose=None): | |
253 | import sys | |
254 | from test import test_support | |
255 | from test import test_genexps | |
256 | test_support.run_doctest(test_genexps, verbose) | |
257 | ||
258 | # verify reference counting | |
259 | if verbose and hasattr(sys, "gettotalrefcount"): | |
260 | import gc | |
261 | counts = [None] * 5 | |
262 | for i in xrange(len(counts)): | |
263 | test_support.run_doctest(test_genexps, verbose) | |
264 | gc.collect() | |
265 | counts[i] = sys.gettotalrefcount() | |
266 | print counts | |
267 | ||
268 | if __name__ == "__main__": | |
269 | test_main(verbose=True) |