Skip to content

Commit 00122c8

Browse files
authored
[3.14] GH-128161: Remove redundant GET_ITER from list comprehension code (GH-134778)
1 parent 266b541 commit 00122c8

File tree

4 files changed

+51
-17
lines changed

4 files changed

+51
-17
lines changed

Lib/test/test_coroutines.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2265,6 +2265,31 @@ def c():
22652265
# before fixing, visible stack from throw would be shorter than from send.
22662266
self.assertEqual(len_send, len_throw)
22672267

2268+
def test_call_aiter_once_in_comprehension(self):
2269+
2270+
class Iterator:
2271+
2272+
def __init__(self):
2273+
self.val = 0
2274+
2275+
async def __anext__(self):
2276+
if self.val == 2:
2277+
raise StopAsyncIteration
2278+
self.val += 1
2279+
return self.val
2280+
2281+
# No __aiter__ method
2282+
2283+
class C:
2284+
2285+
def __aiter__(self):
2286+
return Iterator()
2287+
2288+
async def run():
2289+
return [i async for i in C()]
2290+
2291+
self.assertEqual(run_async(run()), ([], [1,2]))
2292+
22682293

22692294
@unittest.skipIf(
22702295
support.is_emscripten or support.is_wasi,

Lib/test/test_listcomps.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,28 @@ def iter_raises():
750750
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
751751
expected)
752752

753+
def test_only_calls_dunder_iter_once(self):
754+
755+
class Iterator:
756+
757+
def __init__(self):
758+
self.val = 0
759+
760+
def __next__(self):
761+
if self.val == 2:
762+
raise StopIteration
763+
self.val += 1
764+
return self.val
765+
766+
# No __iter__ method
767+
768+
class C:
769+
770+
def __iter__(self):
771+
return Iterator()
772+
773+
self.assertEqual([1,2], [i for i in C()])
774+
753775
__test__ = {'doctests' : doctests}
754776

755777
def load_tests(loader, tests, pattern):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
No longer call ``__iter__`` twice in list comprehensions. This brings the
2+
behavior of list comprehensions in line with other forms of iteration

Python/codegen.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4543,9 +4543,9 @@ codegen_async_comprehension_generator(compiler *c, location loc,
45434543
else {
45444544
/* Sub-iter - calculate on the fly */
45454545
VISIT(c, expr, gen->iter);
4546-
ADDOP(c, LOC(gen->iter), GET_AITER);
45474546
}
45484547
}
4548+
ADDOP(c, LOC(gen->iter), GET_AITER);
45494549

45504550
USE_LABEL(c, start);
45514551
/* Runtime will push a block here, so we need to account for that */
@@ -4757,19 +4757,6 @@ pop_inlined_comprehension_state(compiler *c, location loc,
47574757
return SUCCESS;
47584758
}
47594759

4760-
static inline int
4761-
codegen_comprehension_iter(compiler *c, comprehension_ty comp)
4762-
{
4763-
VISIT(c, expr, comp->iter);
4764-
if (comp->is_async) {
4765-
ADDOP(c, LOC(comp->iter), GET_AITER);
4766-
}
4767-
else {
4768-
ADDOP(c, LOC(comp->iter), GET_ITER);
4769-
}
4770-
return SUCCESS;
4771-
}
4772-
47734760
static int
47744761
codegen_comprehension(compiler *c, expr_ty e, int type,
47754762
identifier name, asdl_comprehension_seq *generators, expr_ty elt,
@@ -4789,9 +4776,7 @@ codegen_comprehension(compiler *c, expr_ty e, int type,
47894776

47904777
outermost = (comprehension_ty) asdl_seq_GET(generators, 0);
47914778
if (is_inlined) {
4792-
if (codegen_comprehension_iter(c, outermost)) {
4793-
goto error;
4794-
}
4779+
VISIT(c, expr, outermost->iter);
47954780
if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) {
47964781
goto error;
47974782
}

0 commit comments

Comments
 (0)