Skip to content

Commit 4fca325

Browse files
committed
gh-136843: Document how multiple inheritance works
1 parent 800d37f commit 4fca325

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

Doc/reference/compound_stmts.rst

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1421,6 +1421,9 @@ is equivalent to ::
14211421
class Foo(object):
14221422
pass
14231423

1424+
There may be one or more base classes; see :ref:`multiple-inheritance` below for more
1425+
information.
1426+
14241427
The class's suite is then executed in a new execution frame (see :ref:`naming`),
14251428
using a newly created local namespace and the original global namespace.
14261429
(Usually, the suite contains mostly function definitions.) When the class's
@@ -1490,6 +1493,97 @@ can be used to create instance variables with different implementation details.
14901493
were introduced in :pep:`318`.
14911494

14921495

1496+
.. _multiple-inheritance:
1497+
1498+
Multiple inheritance
1499+
--------------------
1500+
1501+
Python classes may have multiple base classes, a technique known as
1502+
*multiple inheritance*. The base classes are specified in the class definition
1503+
by listing them in parentheses after the class name, separated by commas.
1504+
For example, the following class definition::
1505+
1506+
class C(A, B):
1507+
pass
1508+
1509+
defines a class ``C`` that inherits from classes ``A`` and ``B``.
1510+
1511+
The :term:`method resolution order` (MRO) is the order in which base classes are
1512+
searched when looking up an attribute on a class. See :ref:`python_2.3_mro` for a
1513+
description of how Python determines the MRO for a class.
1514+
1515+
Multiple inheritance is not always allowed. Attempting to define a class with multiple
1516+
inheritance will raise an error if one of the bases is invalid, if a consistent MRO
1517+
cannot be created, if no valid metaclass can be determined, or if there is an instance
1518+
layout conflict. We'll discuss each of these in turn.
1519+
1520+
First, all base classes must allow subclassing. While most classes allow subclassing,
1521+
some built-in classes do not, such as :class:`bool`::
1522+
1523+
class SubBool(bool): # TypeError
1524+
pass
1525+
1526+
To create a consistent MRO, all bases appear in the order
1527+
they were specified in the base class list and every child class must appear before its
1528+
base classes. Below is an example where this fails::
1529+
1530+
class Base: pass
1531+
class Child(Base): pass
1532+
class Grandchild(Base, Child): pass # TypeError
1533+
1534+
In the MRO of ``Grandchild``, ``Child`` must appear before ``Base`` because it is first
1535+
in the base class list, but it must also appear after ``Base`` because it is a child of
1536+
``Base``. This is a contradiction, so the class cannot be defined.
1537+
1538+
If some of the bases have a custom :term:`metaclass`, the metaclass of the resulting class
1539+
is chosen among the metaclasses of the bases. It must be a metaclass that is a subclass of
1540+
all other candidate metaclasses. If no such metaclass exists, the class cannot be created,
1541+
as explained in :ref:`metaclass-determination`.
1542+
1543+
Finally, the memory layouts of the bases must be compatible. This means that it must be
1544+
possible to compute a *solid base* for the class. A class is a solid base if it has a
1545+
nonempty :attr:`~object.__slots__` definition; some other classes may also be solid bases,
1546+
depending on the Python implementation.
1547+
1548+
.. impl-detail::
1549+
1550+
In CPython, many but not all classes defined in C are solid bases, including most
1551+
builtins but excluding most concrete :class:`Exception` classes. Generally, a C class
1552+
is a solid base if its underlying struct is different in size from its base class.
1553+
1554+
Every class has a solid base. :class:`object`, the base class, has itself as its solid base.
1555+
If there is a single base, the child class's solid base is that class if it is a solid baes,
1556+
or else the base class's solid base. If there are multiple bases, we first find the solid base
1557+
for each base class to produce a list of candidate solid bases. If there is a unique solid base
1558+
that is a subclass of all others, then that class is the solid base. Otherwise, class creation
1559+
fails.
1560+
1561+
Example::
1562+
1563+
class Solid1:
1564+
__slots__ = ("solid1",)
1565+
1566+
class Solid2:
1567+
__slots__ = ("solid2",)
1568+
1569+
class SolidChild(Solid1):
1570+
__slots__ = ("solid_child",)
1571+
1572+
class C1: # solid base is `object`
1573+
pass
1574+
1575+
# OK: solid bases are `Solid1` and `object`, and `Solid1` is a subclass of `object`.
1576+
class C2(Solid1, C1): # solid base is `Solid1`
1577+
pass
1578+
1579+
# OK: solid bases are `SolidChild` and `Solid1`, and `SolidChild` is a subclass of `Solid1`.
1580+
class C3(SolidChild, Solid1): # solid base is `SolidChild`
1581+
pass
1582+
1583+
# Error: solid bases are `Solid1` and `Solid2`, but they are not subclasses of each other.
1584+
class C4(Solid1, Solid2): # error: no single solid base
1585+
pass
1586+
14931587
.. _async:
14941588

14951589
Coroutines

Doc/reference/datamodel.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,8 @@ Resolving MRO entries
27792779
Core support for typing module and generic types.
27802780

27812781

2782+
.. _metaclass-determination:
2783+
27822784
Determining the appropriate metaclass
27832785
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27842786
.. index::

Doc/tutorial/classes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,9 @@ Taken together, these properties make it possible to design reliable and
663663
extensible classes with multiple inheritance. For more detail, see
664664
:ref:`python_2.3_mro`.
665665

666+
In some cases multiple inheritance is not allowed; see :ref:`multiple-inheritance`
667+
for details.
668+
666669

667670
.. _tut-private:
668671

0 commit comments

Comments
 (0)