Skip to content

Commit e5bcff5

Browse files
CharlieZhao95JelleZijlstra
authored andcommitted
[3.9] bpo-46677: Add examples of inheritance and attributes to TypedDict docs. (pythonGH-31349) (pythonGH-31808)
* bpo-46677: Add examples of inheritance and attributes to `TypedDict` docs (pythonGH-31349) Co-authored-by: Jelle Zijlstra <[email protected]> (cherry picked from commit 8a207e0)
1 parent 05c6111 commit e5bcff5

File tree

1 file changed

+106
-12
lines changed

1 file changed

+106
-12
lines changed

Doc/library/typing.rst

Lines changed: 106 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,26 +1056,120 @@ These are not used in annotations. They are building blocks for declaring types.
10561056

10571057
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
10581058

1059-
The type info for introspection can be accessed via ``Point2D.__annotations__``
1060-
and ``Point2D.__total__``. To allow using this feature with older versions
1061-
of Python that do not support :pep:`526`, ``TypedDict`` supports two additional
1062-
equivalent syntactic forms::
1059+
To allow using this feature with older versions of Python that do not
1060+
support :pep:`526`, ``TypedDict`` supports two additional equivalent
1061+
syntactic forms:
1062+
1063+
* Using a literal :class:`dict` as the second argument::
10631064

1064-
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
10651065
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
10661066

1067-
By default, all keys must be present in a TypedDict. It is possible
1068-
to override this by specifying totality.
1067+
* Using keyword arguments::
1068+
1069+
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
1070+
1071+
The functional syntax should also be used when any of the keys are not valid
1072+
:ref:`identifiers`, for example because they are keywords or contain hyphens.
1073+
Example::
1074+
1075+
# raises SyntaxError
1076+
class Point2D(TypedDict):
1077+
in: int # 'in' is a keyword
1078+
x-y: int # name with hyphens
1079+
1080+
# OK, functional syntax
1081+
Point2D = TypedDict('Point2D', {'in': int, 'x-y': int})
1082+
1083+
By default, all keys must be present in a ``TypedDict``. It is possible to
1084+
override this by specifying totality.
10691085
Usage::
10701086

1071-
class point2D(TypedDict, total=False):
1087+
class Point2D(TypedDict, total=False):
10721088
x: int
10731089
y: int
10741090

1075-
This means that a point2D TypedDict can have any of the keys omitted. A type
1076-
checker is only expected to support a literal False or True as the value of
1077-
the total argument. True is the default, and makes all items defined in the
1078-
class body be required.
1091+
# Alternative syntax
1092+
Point2D = TypedDict('Point2D', {'x': int, 'y': int}, total=False)
1093+
1094+
This means that a ``Point2D`` ``TypedDict`` can have any of the keys
1095+
omitted. A type checker is only expected to support a literal ``False`` or
1096+
``True`` as the value of the ``total`` argument. ``True`` is the default,
1097+
and makes all items defined in the class body required.
1098+
1099+
It is possible for a ``TypedDict`` type to inherit from one or more other ``TypedDict`` types
1100+
using the class-based syntax.
1101+
Usage::
1102+
1103+
class Point3D(Point2D):
1104+
z: int
1105+
1106+
``Point3D`` has three items: ``x``, ``y`` and ``z``. It is equivalent to this
1107+
definition::
1108+
1109+
class Point3D(TypedDict):
1110+
x: int
1111+
y: int
1112+
z: int
1113+
1114+
A ``TypedDict`` cannot inherit from a non-TypedDict class,
1115+
notably including :class:`Generic`. For example::
1116+
1117+
class X(TypedDict):
1118+
x: int
1119+
1120+
class Y(TypedDict):
1121+
y: int
1122+
1123+
class Z(object): pass # A non-TypedDict class
1124+
1125+
class XY(X, Y): pass # OK
1126+
1127+
class XZ(X, Z): pass # raises TypeError
1128+
1129+
T = TypeVar('T')
1130+
class XT(X, Generic[T]): pass # raises TypeError
1131+
1132+
A ``TypedDict`` can be introspected via :attr:`__annotations__`,
1133+
:attr:`__total__`, :attr:`__required_keys__`, and :attr:`__optional_keys__`.
1134+
1135+
.. attribute:: __total__
1136+
1137+
``Point2D.__total__`` gives the value of the ``total`` argument.
1138+
Example::
1139+
1140+
>>> from typing import TypedDict
1141+
>>> class Point2D(TypedDict): pass
1142+
>>> Point2D.__total__
1143+
True
1144+
>>> class Point2D(TypedDict, total=False): pass
1145+
>>> Point2D.__total__
1146+
False
1147+
>>> class Point3D(Point2D): pass
1148+
>>> Point3D.__total__
1149+
True
1150+
1151+
.. attribute:: __required_keys__
1152+
.. attribute:: __optional_keys__
1153+
1154+
``Point2D.__required_keys__`` and ``Point2D.__optional_keys__`` return
1155+
:class:`frozenset` objects containing required and non-required keys, respectively.
1156+
Currently the only way to declare both required and non-required keys in the
1157+
same ``TypedDict`` is mixed inheritance, declaring a ``TypedDict`` with one value
1158+
for the ``total`` argument and then inheriting it from another ``TypedDict`` with
1159+
a different value for ``total``.
1160+
Usage::
1161+
1162+
>>> class Point2D(TypedDict, total=False):
1163+
... x: int
1164+
... y: int
1165+
...
1166+
>>> class Point3D(Point2D):
1167+
... z: int
1168+
...
1169+
>>> Point3D.__required_keys__ == frozenset({'z'})
1170+
True
1171+
>>> Point3D.__optional_keys__ == frozenset({'x', 'y'})
1172+
True
10791173

10801174
See :pep:`589` for more examples and detailed rules of using ``TypedDict``.
10811175

0 commit comments

Comments
 (0)