https://github.com/python/cpython/commit/d87e7f35297d34755026173d84a38eedfbed78de commit: d87e7f35297d34755026173d84a38eedfbed78de branch: main author: Mark Shannon <m...@hotpy.org> committer: markshannon <m...@hotpy.org> 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 -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com