Index: Python/compile.c =================================================================== --- Python/compile.c (revision 46597) +++ Python/compile.c (working copy) @@ -609,6 +609,30 @@ return 1; } +/* Try to convert "x in (5, 6, 7)" and "x in [5, 6, 7]" + into "x in set([5, 6, 7])" */ +static int +optimize_in_const_seq(unsigned char *codestr, int lc_inst, PyObject *consts) +{ + PyObject *opt_set, *tuple; + int new_index; + + tuple = PyList_GET_ITEM(consts, GETARG(codestr, lc_inst)); + if (NULL == tuple) + return 1; + + opt_set = PyFrozenSet_New(tuple); + if (NULL == opt_set) + return 1; + new_index = PyList_GET_SIZE(consts); + if(PyList_Append(consts, opt_set)) { + Py_DECREF(opt_set); + return 1; + } + SETARG(codestr, lc_inst, new_index); + return 0; +} + static unsigned int * markblocks(unsigned char *code, int len) { @@ -752,10 +776,22 @@ if (j < 6 || j > 9 || codestr[i+3] != UNARY_NOT || !ISBASICBLOCK(blocks,i,4)) - continue; + goto cmp_op_in_set; SETARG(codestr, i, (j^1)); codestr[i+3] = NOP; - break; + + /* Try to convert "x in (5, 6, 7)" and "x in [5, 6, 7]" + into "x in set([5, 6, 7])" */ + + cmp_op_in_set: + j = GETARG(codestr, i); + tgt = GETARG(codestr, i-3); + if (j < 6 || j > 9 || + codestr[i-3] != LOAD_CONST || + !PyTuple_CheckExact(PyList_GET_ITEM(consts, tgt)) || + optimize_in_const_seq(codestr, i-3, consts)) + continue; + break; /* Replace LOAD_GLOBAL/LOAD_NAME None with LOAD_CONST None */ Index: Lib/test/test_peepholer.py =================================================================== --- Lib/test/test_peepholer.py (revision 46597) +++ Lib/test/test_peepholer.py (working copy) @@ -160,6 +160,29 @@ self.assert_('LOAD_CONST' not in asm) self.assert_('(None)' not in asm) self.assertEqual(asm.split().count('RETURN_VALUE'), 1) + + def test_convert_in_tuple_to_frozenset(self): + # convert "x in (5, 6, 7):" to "x in frozenset([5, 6, 7])" + + def f(x): + if x in (5, 6, 7): + pass + + asm = disassemble(f) + self.assert_('((5, 6, 7))' not in asm) + self.assert_('(frozenset([5, 6, 7]))' in asm) + + def test_convert_in_list_to_frozenset(self): + # convert "x in [5, 6, 7]:" to "x in frozenset([5, 6, 7])" + + def f(x): + if x in [5, 6, 7]: + pass + + asm = disassemble(f) + # The [5, 6, 7] gets optimised to (5, 6, 7) by a different optimiser + self.assert_('((5, 6, 7))' not in asm) + self.assert_('(frozenset([5, 6, 7]))' in asm)