https://github.com/python/cpython/commit/d87e7f35297d34755026173d84a38eedfbed78de
commit: d87e7f35297d34755026173d84a38eedfbed78de
branch: main
author: Mark Shannon <[email protected]>
committer: markshannon <[email protected]>
date: 2025-04-11T09:37:22+01:00
summary:
GH-127682: Only call `__iter__` once in generator expressions. (GH-132351)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2025-04-10-10-29-45.gh-issue-127682.X0HoGz.rst
M Lib/test/test_dis.py
M Lib/test/test_generators.py
M Lib/test/test_genexps.py
M Python/codegen.c
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 58ba86fb43092a..b53a3656429300 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -204,7 +204,6 @@ def bug1333982(x=[]):
LOAD_CONST 1 (<code object <genexpr> at 0x...,
file "%s", line %d>)
MAKE_FUNCTION
LOAD_FAST_BORROW 0 (x)
- GET_ITER
CALL 0
%3d LOAD_SMALL_INT 1
@@ -821,7 +820,6 @@ def foo(x):
MAKE_FUNCTION
SET_FUNCTION_ATTRIBUTE 8 (closure)
LOAD_DEREF 1 (y)
- GET_ITER
CALL 0
CALL 1
RETURN_VALUE
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 8bce42f037478c..3e41c7b9663491 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -268,6 +268,28 @@ def loop():
#This should not raise
loop()
+ def test_genexpr_only_calls_dunder_iter_once(self):
+
+ class Iterator:
+
+ def __init__(self):
+ self.val = 0
+
+ def __next__(self):
+ if self.val == 2:
+ raise StopIteration
+ self.val += 1
+ return self.val
+
+ # No __iter__ method
+
+ class C:
+
+ def __iter__(self):
+ return Iterator()
+
+ self.assertEqual([1,2], list(i for i in C()))
+
class ModifyUnderlyingIterableTest(unittest.TestCase):
iterables = [
diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py
index 7fb58a67368576..fe5f18fa3f88a0 100644
--- a/Lib/test/test_genexps.py
+++ b/Lib/test/test_genexps.py
@@ -123,15 +123,6 @@
>>> list(g)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
-Verify that the outermost for-expression makes an immediate check
-for iterability
-
- >>> (i for i in 6)
- Traceback (most recent call last):
- File "<pyshell#4>", line 1, in -toplevel-
- (i for i in 6)
- TypeError: 'int' object is not iterable
-
Verify late binding for the outermost if-expression
>>> include = (2,4,6,8)
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-10-10-29-45.gh-issue-127682.X0HoGz.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-10-10-29-45.gh-issue-127682.X0HoGz.rst
new file mode 100644
index 00000000000000..b87750eb516e7a
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-10-10-29-45.gh-issue-127682.X0HoGz.rst
@@ -0,0 +1,4 @@
+No longer call ``__iter__`` twice when creating and executing a generator
expression.
+Creating a generator expression from a non-interable will raise only when the
+generator expression is executed.
+This brings the behavior of generator expressions in line with other
generators.
diff --git a/Python/codegen.c b/Python/codegen.c
index 379d37c65ca8e6..35b46dcdc40950 100644
--- a/Python/codegen.c
+++ b/Python/codegen.c
@@ -4775,10 +4775,7 @@ codegen_comprehension(compiler *c, expr_ty e, int type,
}
Py_CLEAR(co);
- if (codegen_comprehension_iter(c, outermost)) {
- goto error;
- }
-
+ VISIT(c, expr, outermost->iter);
ADDOP_I(c, loc, CALL, 0);
if (is_async_comprehension && type != COMP_GENEXP) {
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]