Skip to content
4 changes: 4 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2482,6 +2482,10 @@ types.
Using :func:`super` (and the ``__class__`` :term:`closure variable`) in methods of ``NamedTuple`` subclasses
is unsupported and causes a :class:`TypeError`.

.. versionchanged:: next
Added support for arbitrary multiple inheritance.


.. class:: NewType(name, tp)

Helper class to create low-overhead :ref:`distinct types <distinct>`.
Expand Down
11 changes: 8 additions & 3 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -830,9 +830,9 @@ http.server
is colored by default.
This can be controlled with :ref:`environment variables
<using-on-controlling-color>`.
(Contributed by Hugo van Kemenade in :gh:`146292`.)
(Contributed by Hugo van Kemenade in :gh:`146292`.)


inspect
-------

Expand Down Expand Up @@ -1239,6 +1239,11 @@ typing
as it was incorrectly inferred in runtime before.
(Contributed by Nikita Sobolev in :gh:`137191`.)

* Add support of multiple inheritance with :class:`~typing.NamedTuple`.
Previously, multiple inheritance was only supported if there was exactly
one other base and the base was :class:`typing.Generic`.
(Contributed by Serhiy Storchaka in :gh:`116241`.)


unicodedata
-----------
Expand Down
37 changes: 36 additions & 1 deletion Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8270,7 +8270,42 @@ class X(NamedTuple):

def test_multiple_inheritance(self):
class A:
pass
@property
def x(self):
return 4
@property
def y(self):
return 5
def __len__(self):
return 10

class X(NamedTuple, A):
x: int
self.assertEqual(X.__bases__, (tuple, A))
self.assertEqual(X.__orig_bases__, (NamedTuple, A))
self.assertEqual(X.__mro__, (X, tuple, A, object))

a = X(3)
self.assertEqual(a.x, 3)
self.assertEqual(a.y, 5)
self.assertEqual(len(a), 1)
self.assertEqual(list(a), [3])

class Y(A, NamedTuple):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a test to check the order of the members as well when doing unpacking? And maybe test class Z(X, Y, NamedTuple)? (I don't know if this leads to a MRO incompatibilty though)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be error. This is tested in the next test.

x: int
self.assertEqual(Y.__bases__, (A, tuple))
self.assertEqual(Y.__orig_bases__, (A, NamedTuple))
self.assertEqual(Y.__mro__, (Y, A, tuple, object))

a = Y(3)
self.assertEqual(a.x, 3)
self.assertEqual(a.y, 5)
self.assertEqual(len(a), 10)
self.assertEqual(list(a), [3])

def test_multiple_inheritance_errors(self):
class A(NamedTuple):
x: int
with self.assertRaises(TypeError):
class X(NamedTuple, A):
x: int
Expand Down
4 changes: 0 additions & 4 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3016,10 +3016,6 @@ def __new__(cls, typename, bases, ns):
if "__classcell__" in ns:
raise TypeError(
"uses of super() and __class__ are unsupported in methods of NamedTuple subclasses")
for base in bases:
if base is not _NamedTuple and base is not Generic:
raise TypeError(
'can only inherit from a NamedTuple type and Generic')
Comment on lines -3019 to -3022
Copy link
Copy Markdown
Member

@johnslavik johnslavik Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bases = tuple(tuple if base is _NamedTuple else base for base in bases)
if "__annotations__" in ns:
types = ns["__annotations__"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for arbitrary multiple inheritance with :class:`typing.NamedTuple`.
Loading