Skip to content

Commit a226707

Browse files
committed
pythonGH-127682: Only call __iter__ once in generator expressions. (pythonGH-132351)
1 parent 2b61f6a commit a226707

File tree

5 files changed

+27
-14
lines changed

5 files changed

+27
-14
lines changed

Lib/test/test_dis.py

-2
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ def bug1333982(x=[]):
184184
LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>)
185185
MAKE_FUNCTION
186186
LOAD_FAST 0 (x)
187-
GET_ITER
188187
CALL 0
189188
190189
%3d LOAD_CONST 2 (1)
@@ -765,7 +764,6 @@ def foo(x):
765764
MAKE_FUNCTION
766765
SET_FUNCTION_ATTRIBUTE 8 (closure)
767766
LOAD_DEREF 1 (y)
768-
GET_ITER
769767
CALL 0
770768
CALL 1
771769
RETURN_VALUE

Lib/test/test_generators.py

+22
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,28 @@ def loop():
246246
#This should not raise
247247
loop()
248248

249+
def test_genexpr_only_calls_dunder_iter_once(self):
250+
251+
class Iterator:
252+
253+
def __init__(self):
254+
self.val = 0
255+
256+
def __next__(self):
257+
if self.val == 2:
258+
raise StopIteration
259+
self.val += 1
260+
return self.val
261+
262+
# No __iter__ method
263+
264+
class C:
265+
266+
def __iter__(self):
267+
return Iterator()
268+
269+
self.assertEqual([1,2], list(i for i in C()))
270+
249271

250272
class ModifyUnderlyingIterableTest(unittest.TestCase):
251273
iterables = [

Lib/test/test_genexps.py

-9
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,6 @@
123123
>>> list(g)
124124
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
125125
126-
Verify that the outermost for-expression makes an immediate check
127-
for iterability
128-
129-
>>> (i for i in 6)
130-
Traceback (most recent call last):
131-
File "<pyshell#4>", line 1, in -toplevel-
132-
(i for i in 6)
133-
TypeError: 'int' object is not iterable
134-
135126
Verify late binding for the outermost if-expression
136127
137128
>>> include = (2,4,6,8)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
No longer call ``__iter__`` twice when creating and executing a generator expression.
2+
Creating a generator expression from a non-interable will raise only when the
3+
generator expression is executed.
4+
This brings the behavior of generator expressions in line with other generators.

Python/compile.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -5910,9 +5910,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
59105910
}
59115911
Py_CLEAR(co);
59125912

5913-
if (compiler_comprehension_iter(c, outermost)) {
5914-
goto error;
5915-
}
5913+
VISIT(c, expr, outermost->iter);
59165914

59175915
ADDOP_I(c, loc, CALL, 0);
59185916

0 commit comments

Comments
 (0)