Skip to content

Commit 28f20a6

Browse files
[3.10] bpo-46677: Add examples of inheritance and attributes to TypedDict docs (GH-31349) (GH-31815)
Co-authored-by: Jelle Zijlstra <[email protected]> (cherry picked from commit 8a207e0) Co-authored-by: Charlie Zhao <[email protected]>
1 parent 393e2bf commit 28f20a6

File tree

1 file changed

+88
-3
lines changed

1 file changed

+88
-3
lines changed

Doc/library/typing.rst

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,16 +1388,25 @@ These are not used in annotations. They are building blocks for declaring types.
13881388

13891389
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
13901390

1391-
The type info for introspection can be accessed via ``Point2D.__annotations__``,
1392-
``Point2D.__total__``, ``Point2D.__required_keys__``, and
1393-
``Point2D.__optional_keys__``.
13941391
To allow using this feature with older versions of Python that do not
13951392
support :pep:`526`, ``TypedDict`` supports two additional equivalent
13961393
syntactic forms::
13971394

13981395
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
13991396
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
14001397

1398+
The functional syntax should also be used when any of the keys are not valid
1399+
:ref:`identifiers`, for example because they are keywords or contain hyphens.
1400+
Example::
1401+
1402+
# raises SyntaxError
1403+
class Point2D(TypedDict):
1404+
in: int # 'in' is a keyword
1405+
x-y: int # name with hyphens
1406+
1407+
# OK, functional syntax
1408+
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
1409+
14011410
By default, all keys must be present in a ``TypedDict``. It is possible to
14021411
override this by specifying totality.
14031412
Usage::
@@ -1411,6 +1420,82 @@ These are not used in annotations. They are building blocks for declaring types.
14111420
``True`` as the value of the ``total`` argument. ``True`` is the default,
14121421
and makes all items defined in the class body required.
14131422

1423+
It is possible for a ``TypedDict`` type to inherit from one or more other ``TypedDict`` types
1424+
using the class-based syntax.
1425+
Usage::
1426+
1427+
class Point3D(Point2D):
1428+
z: int
1429+
1430+
``Point3D`` has three items: ``x``, ``y`` and ``z``. It is equivalent to this
1431+
definition::
1432+
1433+
class Point3D(TypedDict):
1434+
x: int
1435+
y: int
1436+
z: int
1437+
1438+
A ``TypedDict`` cannot inherit from a non-TypedDict class,
1439+
notably including :class:`Generic`. For example::
1440+
1441+
class X(TypedDict):
1442+
x: int
1443+
1444+
class Y(TypedDict):
1445+
y: int
1446+
1447+
class Z(object): pass # A non-TypedDict class
1448+
1449+
class XY(X, Y): pass # OK
1450+
1451+
class XZ(X, Z): pass # raises TypeError
1452+
1453+
T = TypeVar('T')
1454+
class XT(X, Generic[T]): pass # raises TypeError
1455+
1456+
A ``TypedDict`` can be introspected via annotations dicts
1457+
(see :ref:`annotations-howto` for more information on annotations best practices),
1458+
:attr:`__total__`, :attr:`__required_keys__`, and :attr:`__optional_keys__`.
1459+
1460+
.. attribute:: __total__
1461+
1462+
``Point2D.__total__`` gives the value of the ``total`` argument.
1463+
Example::
1464+
1465+
>>> from typing import TypedDict
1466+
>>> class Point2D(TypedDict): pass
1467+
>>> Point2D.__total__
1468+
True
1469+
>>> class Point2D(TypedDict, total=False): pass
1470+
>>> Point2D.__total__
1471+
False
1472+
>>> class Point3D(Point2D): pass
1473+
>>> Point3D.__total__
1474+
True
1475+
1476+
.. attribute:: __required_keys__
1477+
.. attribute:: __optional_keys__
1478+
1479+
``Point2D.__required_keys__`` and ``Point2D.__optional_keys__`` return
1480+
:class:`frozenset` objects containing required and non-required keys, respectively.
1481+
Currently the only way to declare both required and non-required keys in the
1482+
same ``TypedDict`` is mixed inheritance, declaring a ``TypedDict`` with one value
1483+
for the ``total`` argument and then inheriting it from another ``TypedDict`` with
1484+
a different value for ``total``.
1485+
Usage::
1486+
1487+
>>> class Point2D(TypedDict, total=False):
1488+
... x: int
1489+
... y: int
1490+
...
1491+
>>> class Point3D(Point2D):
1492+
... z: int
1493+
...
1494+
>>> Point3D.__required_keys__ == frozenset({'z'})
1495+
True
1496+
>>> Point3D.__optional_keys__ == frozenset({'x', 'y'})
1497+
True
1498+
14141499
See :pep:`589` for more examples and detailed rules of using ``TypedDict``.
14151500

14161501
.. versionadded:: 3.8

0 commit comments

Comments
 (0)