From 1f1a34c3145781628e10534440017b3b43211a60 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 20 Dec 2017 15:58:21 +0100 Subject: [PATCH] bpo-32379: Faster MRO computation for single inheritance (#4932) * bpo-32379: Faster MRO computation for single inheritance --- Lib/test/test_descr.py | 6 +++ .../2017-12-19-21-14-41.bpo-32379.B7mOmI.rst | 1 + Objects/typeobject.c | 40 +++++++++++++++++-- 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index ced25f3fc44..d24d005ccfa 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 00000000000..1050c61b9ec --- /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 aa907018859..849c6dc1929 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