Browse Source

bpo-32925: Optimized iterating and containing test for literal lists (GH-5842)

consisting of non-constants: `x in [a, b]` and `for x in [a, b]`.
The case of all constant elements already was optimized.
pull/5492/merge
Serhiy Storchaka 9 years ago
committed by GitHub
parent
commit
3f7e9aa2ef
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      Lib/test/test_peepholer.py
  2. 3
      Misc/NEWS.d/next/Core and Builtins/2018-02-24-00-07-05.bpo-32925.e-7Ufh.rst
  3. 19
      Python/ast_opt.c

24
Lib/test/test_peepholer.py

@ -3,6 +3,19 @@ import unittest
from test.bytecode_helper import BytecodeTestCase from test.bytecode_helper import BytecodeTestCase
def count_instr_recursively(f, opname):
count = 0
for instr in dis.get_instructions(f):
if instr.opname == opname:
count += 1
if hasattr(f, '__code__'):
f = f.__code__
for c in f.co_consts:
if hasattr(c, 'co_code'):
count += count_instr_recursively(c, opname)
return count
class TestTranforms(BytecodeTestCase): class TestTranforms(BytecodeTestCase):
def test_unot(self): def test_unot(self):
@ -311,6 +324,17 @@ class TestTranforms(BytecodeTestCase):
self.assertFalse(instr.opname.startswith('BINARY_')) self.assertFalse(instr.opname.startswith('BINARY_'))
self.assertFalse(instr.opname.startswith('BUILD_')) self.assertFalse(instr.opname.startswith('BUILD_'))
def test_in_literal_list(self):
def containtest():
return x in [a, b]
self.assertEqual(count_instr_recursively(containtest, 'BUILD_LIST'), 0)
def test_iterate_literal_list(self):
def forloop():
for x in [a, b]:
pass
self.assertEqual(count_instr_recursively(forloop, 'BUILD_LIST'), 0)
class TestBuglets(unittest.TestCase): class TestBuglets(unittest.TestCase):

3
Misc/NEWS.d/next/Core and Builtins/2018-02-24-00-07-05.bpo-32925.e-7Ufh.rst

@ -0,0 +1,3 @@
Optimized iterating and containing test for literal lists consisting of
non-constants: ``x in [a, b]`` and ``for x in [a, b]``. The case of all
constant elements already was optimized.

19
Python/ast_opt.c

@ -369,7 +369,8 @@ fold_subscr(expr_ty node, PyArena *arena, int optimize)
} }
/* Change literal list or set of constants into constant /* Change literal list or set of constants into constant
tuple or frozenset respectively.
tuple or frozenset respectively. Change literal list of
non-constants into tuple.
Used for right operand of "in" and "not in" tests and for iterable Used for right operand of "in" and "not in" tests and for iterable
in "for" loop and comprehensions. in "for" loop and comprehensions.
*/ */
@ -378,7 +379,21 @@ fold_iter(expr_ty arg, PyArena *arena, int optimize)
{ {
PyObject *newval; PyObject *newval;
if (arg->kind == List_kind) { if (arg->kind == List_kind) {
newval = make_const_tuple(arg->v.List.elts);
/* First change a list into tuple. */
asdl_seq *elts = arg->v.List.elts;
Py_ssize_t n = asdl_seq_LEN(elts);
for (Py_ssize_t i = 0; i < n; i++) {
expr_ty e = (expr_ty)asdl_seq_GET(elts, i);
if (e->kind == Starred_kind) {
return 1;
}
}
expr_context_ty ctx = arg->v.List.ctx;
arg->kind = Tuple_kind;
arg->v.Tuple.elts = elts;
arg->v.Tuple.ctx = ctx;
/* Try to create a constant tuple. */
newval = make_const_tuple(elts);
} }
else if (arg->kind == Set_kind) { else if (arg->kind == Set_kind) {
newval = make_const_tuple(arg->v.Set.elts); newval = make_const_tuple(arg->v.Set.elts);

Loading…
Cancel
Save