]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-32379: Faster MRO computation for single inheritance (#4932)
authorAntoine Pitrou <pitrou@free.fr>
Wed, 20 Dec 2017 14:58:21 +0000 (15:58 +0100)
committerGitHub <noreply@github.com>
Wed, 20 Dec 2017 14:58:21 +0000 (15:58 +0100)
* bpo-32379: Faster MRO computation for single inheritance

Lib/test/test_descr.py
Misc/NEWS.d/next/Core and Builtins/2017-12-19-21-14-41.bpo-32379.B7mOmI.rst [new file with mode: 0644]
Objects/typeobject.c

index ced25f3fc4424400063d90aa66cad43df07b2559..d24d005ccfaa9403a4bc1b8023c97fc980aa7b79 100644 (file)
@@ -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 (file)
index 0000000..1050c61
--- /dev/null
@@ -0,0 +1 @@
+Make MRO computation faster when a class inherits from a single base.
index aa907018859eb2f674ffbcc0a002ed10c2237568..849c6dc192948203832dfef71e1842e88be8af2b 100644 (file)
@@ -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