Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d87e7f3

Browse filesBrowse files
authored
GH-127682: Only call __iter__ once in generator expressions. (GH-132351)
1 parent bc0b94b commit d87e7f3
Copy full SHA for d87e7f3

File tree

Expand file treeCollapse file tree

5 files changed

+27
-15
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+27
-15
lines changed

‎Lib/test/test_dis.py

Copy file name to clipboardExpand all lines: Lib/test/test_dis.py
-2Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ def bug1333982(x=[]):
204204
LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>)
205205
MAKE_FUNCTION
206206
LOAD_FAST_BORROW 0 (x)
207-
GET_ITER
208207
CALL 0
209208
210209
%3d LOAD_SMALL_INT 1
@@ -821,7 +820,6 @@ def foo(x):
821820
MAKE_FUNCTION
822821
SET_FUNCTION_ATTRIBUTE 8 (closure)
823822
LOAD_DEREF 1 (y)
824-
GET_ITER
825823
CALL 0
826824
CALL 1
827825
RETURN_VALUE

‎Lib/test/test_generators.py

Copy file name to clipboardExpand all lines: Lib/test/test_generators.py
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,28 @@ def loop():
268268
#This should not raise
269269
loop()
270270

271+
def test_genexpr_only_calls_dunder_iter_once(self):
272+
273+
class Iterator:
274+
275+
def __init__(self):
276+
self.val = 0
277+
278+
def __next__(self):
279+
if self.val == 2:
280+
raise StopIteration
281+
self.val += 1
282+
return self.val
283+
284+
# No __iter__ method
285+
286+
class C:
287+
288+
def __iter__(self):
289+
return Iterator()
290+
291+
self.assertEqual([1,2], list(i for i in C()))
292+
271293

272294
class ModifyUnderlyingIterableTest(unittest.TestCase):
273295
iterables = [

‎Lib/test/test_genexps.py

Copy file name to clipboardExpand all lines: Lib/test/test_genexps.py
-9Lines changed: 0 additions & 9 deletions
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)
+4Lines changed: 4 additions & 0 deletions
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/codegen.c

Copy file name to clipboardExpand all lines: Python/codegen.c
+1-4Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4775,10 +4775,7 @@ codegen_comprehension(compiler *c, expr_ty e, int type,
47754775
}
47764776
Py_CLEAR(co);
47774777

4778-
if (codegen_comprehension_iter(c, outermost)) {
4779-
goto error;
4780-
}
4781-
4778+
VISIT(c, expr, outermost->iter);
47824779
ADDOP_I(c, loc, CALL, 0);
47834780

47844781
if (is_async_comprehension && type != COMP_GENEXP) {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.