Skip to content

Commit 8a207e0

Browse files
bpo-46677: Add examples of inheritance and attributes to TypedDict docs (GH-31349)
Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 6c83c8e commit 8a207e0

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
@@ -1469,9 +1469,6 @@ These are not used in annotations. They are building blocks for declaring types.
14691469

14701470
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
14711471

1472-
The type info for introspection can be accessed via ``Point2D.__annotations__``,
1473-
``Point2D.__total__``, ``Point2D.__required_keys__``, and
1474-
``Point2D.__optional_keys__``.
14751472
To allow using this feature with older versions of Python that do not
14761473
support :pep:`526`, ``TypedDict`` supports two additional equivalent
14771474
syntactic forms:
@@ -1488,6 +1485,18 @@ These are not used in annotations. They are building blocks for declaring types.
14881485
The keyword-argument syntax is deprecated in 3.11 and will be removed
14891486
in 3.13. It may also be unsupported by static type checkers.
14901487

1488+
The functional syntax should also be used when any of the keys are not valid
1489+
:ref:`identifiers`, for example because they are keywords or contain hyphens.
1490+
Example::
1491+
1492+
# raises SyntaxError
1493+
class Point2D(TypedDict):
1494+
in: int # 'in' is a keyword
1495+
x-y: int # name with hyphens
1496+
1497+
# OK, functional syntax
1498+
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
1499+
14911500
By default, all keys must be present in a ``TypedDict``. It is possible to
14921501
override this by specifying totality.
14931502
Usage::
@@ -1504,6 +1513,82 @@ These are not used in annotations. They are building blocks for declaring types.
15041513
``True`` as the value of the ``total`` argument. ``True`` is the default,
15051514
and makes all items defined in the class body required.
15061515

1516+
It is possible for a ``TypedDict`` type to inherit from one or more other ``TypedDict`` types
1517+
using the class-based syntax.
1518+
Usage::
1519+
1520+
class Point3D(Point2D):
1521+
z: int
1522+
1523+
``Point3D`` has three items: ``x``, ``y`` and ``z``. It is equivalent to this
1524+
definition::
1525+
1526+
class Point3D(TypedDict):
1527+
x: int
1528+
y: int
1529+
z: int
1530+
1531+
A ``TypedDict`` cannot inherit from a non-TypedDict class,
1532+
notably including :class:`Generic`. For example::
1533+
1534+
class X(TypedDict):
1535+
x: int
1536+
1537+
class Y(TypedDict):
1538+
y: int
1539+
1540+
class Z(object): pass # A non-TypedDict class
1541+
1542+
class XY(X, Y): pass # OK
1543+
1544+
class XZ(X, Z): pass # raises TypeError
1545+
1546+
T = TypeVar('T')
1547+
class XT(X, Generic[T]): pass # raises TypeError
1548+
1549+
A ``TypedDict`` can be introspected via annotations dicts
1550+
(see :ref:`annotations-howto` for more information on annotations best practices),
1551+
:attr:`__total__`, :attr:`__required_keys__`, and :attr:`__optional_keys__`.
1552+
1553+
.. attribute:: __total__
1554+
1555+
``Point2D.__total__`` gives the value of the ``total`` argument.
1556+
Example::
1557+
1558+
>>> from typing import TypedDict
1559+
>>> class Point2D(TypedDict): pass
1560+
>>> Point2D.__total__
1561+
True
1562+
>>> class Point2D(TypedDict, total=False): pass
1563+
>>> Point2D.__total__
1564+
False
1565+
>>> class Point3D(Point2D): pass
1566+
>>> Point3D.__total__
1567+
True
1568+
1569+
.. attribute:: __required_keys__
1570+
.. attribute:: __optional_keys__
1571+
1572+
``Point2D.__required_keys__`` and ``Point2D.__optional_keys__`` return
1573+
:class:`frozenset` objects containing required and non-required keys, respectively.
1574+
Currently the only way to declare both required and non-required keys in the
1575+
same ``TypedDict`` is mixed inheritance, declaring a ``TypedDict`` with one value
1576+
for the ``total`` argument and then inheriting it from another ``TypedDict`` with
1577+
a different value for ``total``.
1578+
Usage::
1579+
1580+
>>> class Point2D(TypedDict, total=False):
1581+
... x: int
1582+
... y: int
1583+
...
1584+
>>> class Point3D(Point2D):
1585+
... z: int
1586+
...
1587+
>>> Point3D.__required_keys__ == frozenset({'z'})
1588+
True
1589+
>>> Point3D.__optional_keys__ == frozenset({'x', 'y'})
1590+
True
1591+
15071592
See :pep:`589` for more examples and detailed rules of using ``TypedDict``.
15081593

15091594
.. versionadded:: 3.8

0 commit comments

Comments
 (0)