Skip to content

Commit 1f1a34c

Browse files
authored
bpo-32379: Faster MRO computation for single inheritance (#4932)
* bpo-32379: Faster MRO computation for single inheritance
1 parent 776407f commit 1f1a34c

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

Lib/test/test_descr.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,12 @@ class C(A):
17831783
def f(self): return "C"
17841784
class D(B, C):
17851785
pass
1786+
self.assertEqual(A.mro(), [A, object])
1787+
self.assertEqual(A.__mro__, (A, object))
1788+
self.assertEqual(B.mro(), [B, A, object])
1789+
self.assertEqual(B.__mro__, (B, A, object))
1790+
self.assertEqual(C.mro(), [C, A, object])
1791+
self.assertEqual(C.__mro__, (C, A, object))
17861792
self.assertEqual(D.mro(), [D, B, C, A, object])
17871793
self.assertEqual(D.__mro__, (D, B, C, A, object))
17881794
self.assertEqual(D().f(), "C")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make MRO computation faster when a class inherits from a single base.

Objects/typeobject.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,36 @@ mro_implementation(PyTypeObject *type)
17611761
return NULL;
17621762
}
17631763

1764+
bases = type->tp_bases;
1765+
n = PyTuple_GET_SIZE(bases);
1766+
if (n == 1) {
1767+
/* Fast path: if there is a single base, constructing the MRO
1768+
* is trivial.
1769+
*/
1770+
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
1771+
Py_ssize_t k;
1772+
1773+
if (base->tp_mro == NULL) {
1774+
PyErr_Format(PyExc_TypeError,
1775+
"Cannot extend an incomplete type '%.100s'",
1776+
base->tp_name);
1777+
return NULL;
1778+
}
1779+
k = PyTuple_GET_SIZE(base->tp_mro);
1780+
result = PyTuple_New(k + 1);
1781+
if (result == NULL) {
1782+
return NULL;
1783+
}
1784+
Py_INCREF(type);
1785+
PyTuple_SET_ITEM(result, 0, (PyObject *) type);
1786+
for (i = 0; i < k; i++) {
1787+
PyObject *cls = PyTuple_GET_ITEM(base->tp_mro, i);
1788+
Py_INCREF(cls);
1789+
PyTuple_SET_ITEM(result, i + 1, cls);
1790+
}
1791+
return result;
1792+
}
1793+
17641794
/* Find a superclass linearization that honors the constraints
17651795
of the explicit lists of bases and the constraints implied by
17661796
each base class.
@@ -1770,9 +1800,6 @@ mro_implementation(PyTypeObject *type)
17701800
to_merge is the declared list of bases.
17711801
*/
17721802

1773-
bases = type->tp_bases;
1774-
n = PyTuple_GET_SIZE(bases);
1775-
17761803
to_merge = PyList_New(n+1);
17771804
if (to_merge == NULL)
17781805
return NULL;
@@ -1830,7 +1857,12 @@ static PyObject *
18301857
type_mro_impl(PyTypeObject *self)
18311858
/*[clinic end generated code: output=bffc4a39b5b57027 input=28414f4e156db28d]*/
18321859
{
1833-
return mro_implementation(self);
1860+
PyObject *seq;
1861+
seq = mro_implementation(self);
1862+
if (seq != NULL && !PyList_Check(seq)) {
1863+
Py_SETREF(seq, PySequence_List(seq));
1864+
}
1865+
return seq;
18341866
}
18351867

18361868
static int

0 commit comments

Comments
 (0)