Index: Objects/rangeobject.c =================================================================== --- Objects/rangeobject.c (revision 74971) +++ Objects/rangeobject.c (working copy) @@ -273,12 +273,63 @@ r->start, r->stop, r->step); } +static int +range_contains(rangeobject *r, PyObject *ob) { + if (PyLong_Check(ob)) { + int cmp1, cmp2, cmp3; + PyObject *tmp1 = NULL; + PyObject *tmp2 = NULL; + PyObject *zero = NULL; + int result = -1; + + if ((zero = PyLong_FromLong(0)) == NULL) // MemoryError in int(0) + goto end; + + /* Check if the value can possibly be in the range. */ + if ((cmp1 = PyObject_RichCompareBool(r->step, zero, Py_GT)) == -1) + goto end; + if (cmp1 == 1) { // positive steps + cmp2 = PyObject_RichCompareBool(r->start, ob, Py_LE); // start <= ob + cmp3 = PyObject_RichCompareBool(ob, r->stop, Py_LT); // ob < stop + } + else { // negative steps + cmp2 = PyObject_RichCompareBool(ob, r->start, Py_LE); // ob <= start + cmp3 = PyObject_RichCompareBool(r->stop, ob, Py_LT); // stop < ob + } + + if (cmp2 == -1 || cmp3 == -1) // TypeError + goto end; + if (cmp2 == 0 || cmp3 == 0) { // ob outside of range + result = 0; + goto end; + } + + /* Check if the stride does not invalidate ob's membership. */ + if ((tmp1 = PyNumber_Subtract(ob, r->start)) == NULL) + goto end; + if ((tmp2 = PyNumber_Remainder(tmp1, r->step)) == NULL) + goto end; + // result = (int(ob) - start % step) == 0 + result = PyObject_RichCompareBool(tmp2, zero, Py_EQ); + + end: + Py_XDECREF(tmp1); + Py_XDECREF(tmp2); + Py_XDECREF(zero); + return result; + } + return (int)_PySequence_IterSearch((PyObject*)r, ob, PY_ITERSEARCH_CONTAINS); +} + static PySequenceMethods range_as_sequence = { (lenfunc)range_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ (ssizeargfunc)range_item, /* sq_item */ 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)range_contains, /* sq_contains */ }; static PyObject * range_iter(PyObject *seq); Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 74971) +++ Misc/NEWS (working copy) @@ -12,6 +12,8 @@ Core and Builtins ----------------- +- Issue #1766304: Improve performance of membership tests on range objects. + - Issue #6713: Improve performance of integer -> string conversions. - Issue #6846: Fix bug where bytearray.pop() returns negative integers. Index: Doc/library/functions.rst =================================================================== --- Doc/library/functions.rst (revision 74971) +++ Doc/library/functions.rst (working copy) @@ -925,7 +925,11 @@ >>> list(range(1, 0)) [] + .. versionchanged:: 3.2 + Testing integers for membership takes constant time instead of + iterating through all items. + .. function:: repr(object) Return a string containing a printable representation of an object. For many