[Python-checkins] bpo-32379: Faster MRO computation for single inheritance (#4932)

Antoine Pitrou webhook-mailer at python.org
Wed Dec 20 09:58:24 EST 2017


https://github.com/python/cpython/commit/1f1a34c3145781628e10534440017b3b43211a60
commit: 1f1a34c3145781628e10534440017b3b43211a60
branch: master
author: Antoine Pitrou <pitrou at free.fr>
committer: GitHub <noreply at github.com>
date: 2017-12-20T15:58:21+01:00
summary:

bpo-32379: Faster MRO computation for single inheritance (#4932)

* bpo-32379: Faster MRO computation for single inheritance

files:
A Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst
M Lib/test/test_descr.py
M Objects/typeobject.c

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 @@ class C(A):
             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



More information about the Python-checkins mailing list