diff options
author | Antoine Pitrou <pitrou@free.fr> | 2017-12-20 14:58:21 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-20 14:58:21 (GMT) |
commit | 1f1a34c3145781628e10534440017b3b43211a60 (patch) | |
tree | a69adc703ecdbd1749bc9b6671d73d04742c9843 | |
parent | 776407fe893fd42972c7e3f71423d9d86741d07c (diff) | |
download | cpython-1f1a34c3145781628e10534440017b3b43211a60.zip cpython-1f1a34c3145781628e10534440017b3b43211a60.tar.gz cpython-1f1a34c3145781628e10534440017b3b43211a60.tar.bz2 |
bpo-32379: Faster MRO computation for single inheritance (#4932)
* bpo-32379: Faster MRO computation for single inheritance
-rw-r--r-- | Lib/test/test_descr.py | 6 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst | 1 | ||||
-rw-r--r-- | Objects/typeobject.c | 40 |
3 files changed, 43 insertions, 4 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index ced25f3..d24d005 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1783,6 +1783,12 @@ order (MRO) for bases """ def f(self): return "C" class D(B, C): pass + self.assertEqual(A.mro(), [A, object]) + self.assertEqual(A.__mro__, (A, object)) + self.assertEqual(B.mro(), [B, A, object]) + self.assertEqual(B.__mro__, (B, A, object)) + self.assertEqual(C.mro(), [C, A, object]) + self.assertEqual(C.__mro__, (C, A, object)) self.assertEqual(D.mro(), [D, B, C, A, object]) self.assertEqual(D.__mro__, (D, B, C, A, object)) self.assertEqual(D().f(), "C") diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst b/Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst new file mode 100644 index 0000000..1050c61 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst @@ -0,0 +1 @@ +Make MRO computation faster when a class inherits from a single base. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index aa90701..849c6dc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1761,6 +1761,36 @@ mro_implementation(PyTypeObject *type) return NULL; } + bases = type->tp_bases; + n = PyTuple_GET_SIZE(bases); + if (n == 1) { + /* Fast path: if there is a single base, constructing the MRO + * is trivial. + */ + PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0); + Py_ssize_t k; + + if (base->tp_mro == NULL) { + PyErr_Format(PyExc_TypeError, + "Cannot extend an incomplete type '%.100s'", + base->tp_name); + return NULL; + } + k = PyTuple_GET_SIZE(base->tp_mro); + result = PyTuple_New(k + 1); + if (result == NULL) { + return NULL; + } + Py_INCREF(type); + PyTuple_SET_ITEM(result, 0, (PyObject *) type); + for (i = 0; i < k; i++) { + PyObject *cls = PyTuple_GET_ITEM(base->tp_mro, i); + Py_INCREF(cls); + PyTuple_SET_ITEM(result, i + 1, cls); + } + return result; + } + /* Find a superclass linearization that honors the constraints of the explicit lists of bases and the constraints implied by each base class. @@ -1770,9 +1800,6 @@ mro_implementation(PyTypeObject *type) to_merge is the declared list of bases. */ - bases = type->tp_bases; - n = PyTuple_GET_SIZE(bases); - to_merge = PyList_New(n+1); if (to_merge == NULL) return NULL; @@ -1830,7 +1857,12 @@ static PyObject * type_mro_impl(PyTypeObject *self) /*[clinic end generated code: output=bffc4a39b5b57027 input=28414f4e156db28d]*/ { - return mro_implementation(self); + PyObject *seq; + seq = mro_implementation(self); + if (seq != NULL && !PyList_Check(seq)) { + Py_SETREF(seq, PySequence_List(seq)); + } + return seq; } static int |