@@ -29,10 +29,105 @@ arguments.
2929Type aliases
3030------------
3131
32- A type alias is defined by assigning the type to the alias::
32+ A type alias is defined by assigning the type to the alias. In this example,
33+ ``Vector `` and ``List[float] `` will be treated as interchangeable synonyms::
3334
35+ from typing import List
3436 Vector = List[float]
3537
38+ def scale(scalar: float, vector: Vector) -> Vector:
39+ return [scalar * num for num in vector]
40+
41+ # typechecks; a list of floats qualifies as a Vector.
42+ new_vector = scale(2.0, [1.0, -4.2, 5.4])
43+
44+ Type aliases are useful for simplifying complex type signatures. For example::
45+
46+ from typing import Dict, Tuple, List
47+
48+ ConnectionOptions = Dict[str, str]
49+ Address = Tuple[str, int]
50+ Server = Tuple[Address, ConnectionOptions]
51+
52+ def broadcast_message(message: str, servers: List[Server]) -> None:
53+ ...
54+
55+ # The static type checker will treat the previous type signature as
56+ # being exactly equivalent to this one.
57+ def broadcast_message(
58+ message: str,
59+ servers: List[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
60+ ...
61+
62+ NewType
63+ -------
64+
65+ Use the ``NewType `` helper function to create distinct types::
66+
67+ from typing import NewType
68+
69+ UserId = NewType('UserId', int)
70+ some_id = UserId(524313)
71+
72+ The static type checker will treat the new type as if it were a subclass
73+ of the original type. This is useful in helping catch logical errors::
74+
75+ def get_user_name(user_id: UserId) -> str:
76+ ...
77+
78+ # typechecks
79+ user_a = get_user_name(UserId(42351))
80+
81+ # does not typecheck; an int is not a UserId
82+ user_b = get_user_name(-1)
83+
84+ You may still perform all ``int `` operations on a variable of type ``UserId ``,
85+ but the result will always be of type ``int ``. This lets you pass in a
86+ ``UserId `` wherever an ``int `` might be expected, but will prevent you from
87+ accidentally creating a ``UserId `` in an invalid way::
88+
89+ # `output` is of type `int`, not `UserId`
90+ output = UserId(23413) + UserId(54341)
91+
92+ Note that these checks are enforced only by the static type checker. At runtime
93+ the statement ``Derived = NewType('Derived', Base) `` will make ``Derived `` a
94+ function that immediately returns whatever parameter you pass it. That means
95+ the expression ``Derived(some_value) `` does not create a new class or introduce
96+ any overhead beyond that of a regular function call.
97+
98+ More precisely, the expression ``some_value is Derived(some_value) `` is always
99+ true at runtime.
100+
101+ This also means that it is not possible to create a subtype of ``Derived ``
102+ since it is an identity function at runtime, not an actual type. Similarly, it
103+ is not possible to create another ``NewType `` based on a ``Derived `` type::
104+
105+ from typing import NewType
106+
107+ UserId = NewType('UserId', int)
108+
109+ # Fails at runtime and does not typecheck
110+ class AdminUserId(UserId): pass
111+
112+ # Also does not typecheck
113+ ProUserId = NewType('ProUserId', UserId)
114+
115+ See :pep: `484 ` for more details.
116+
117+ .. note ::
118+
119+ Recall that the use of a type alias declares two types to be *equivalent * to
120+ one another. Doing ``Alias = Original `` will make the static type checker
121+ treat ``Alias `` as being *exactly equivalent * to ``Original `` in all cases.
122+ This is useful when you want to simplify complex type signatures.
123+
124+ In contrast, ``NewType `` declares one type to be a *subtype * of another.
125+ Doing ``Derived = NewType('Derived', Original) `` will make the static type
126+ checker treat ``Derived `` as a *subclass * of ``Original ``, which means a
127+ value of type ``Original `` cannot be used in places where a value of type
128+ ``Derived `` is expected. This is useful when you want to prevent logic
129+ errors with minimal runtime cost.
130+
36131Callable
37132--------
38133
0 commit comments