mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
GH-127682: Only call __iter__
once in generator expressions. (GH-132351)
This commit is contained in:
parent
bc0b94b30c
commit
d87e7f3529
5 changed files with 27 additions and 15 deletions
|
@ -204,7 +204,6 @@ dis_bug1333982 = """\
|
|||
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 @@ Disassembly of <code object foo at 0x..., file "%s", line %d>:
|
|||
MAKE_FUNCTION
|
||||
SET_FUNCTION_ATTRIBUTE 8 (closure)
|
||||
LOAD_DEREF 1 (y)
|
||||
GET_ITER
|
||||
CALL 0
|
||||
CALL 1
|
||||
RETURN_VALUE
|
||||
|
|
|
@ -268,6 +268,28 @@ class GeneratorTest(unittest.TestCase):
|
|||
#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 = [
|
||||
|
|
|
@ -123,15 +123,6 @@ Verify early binding for the outermost for-expression
|
|||
>>> 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)
|
||||
|
|
|
@ -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.
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue