Expand documentation about type aliases and NewType in the typing module.
By Michael Lee.
This commit is contained in:
parent
1050d2d0c7
commit
342e800e97
|
@ -29,10 +29,105 @@ arguments.
|
|||
Type aliases
|
||||
------------
|
||||
|
||||
A type alias is defined by assigning the type to the alias::
|
||||
A type alias is defined by assigning the type to the alias. In this example,
|
||||
``Vector`` and ``List[float]`` will be treated as interchangeable synonyms::
|
||||
|
||||
from typing import List
|
||||
Vector = List[float]
|
||||
|
||||
def scale(scalar: float, vector: Vector) -> Vector:
|
||||
return [scalar * num for num in vector]
|
||||
|
||||
# typechecks; a list of floats qualifies as a Vector.
|
||||
new_vector = scale(2.0, [1.0, -4.2, 5.4])
|
||||
|
||||
Type aliases are useful for simplifying complex type signatures. For example::
|
||||
|
||||
from typing import Dict, Tuple, List
|
||||
|
||||
ConnectionOptions = Dict[str, str]
|
||||
Address = Tuple[str, int]
|
||||
Server = Tuple[Address, ConnectionOptions]
|
||||
|
||||
def broadcast_message(message: str, servers: List[Server]) -> None:
|
||||
...
|
||||
|
||||
# The static type checker will treat the previous type signature as
|
||||
# being exactly equivalent to this one.
|
||||
def broadcast_message(
|
||||
message: str,
|
||||
servers: List[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
|
||||
...
|
||||
|
||||
NewType
|
||||
-------
|
||||
|
||||
Use the ``NewType`` helper function to create distinct types::
|
||||
|
||||
from typing import NewType
|
||||
|
||||
UserId = NewType('UserId', int)
|
||||
some_id = UserId(524313)
|
||||
|
||||
The static type checker will treat the new type as if it were a subclass
|
||||
of the original type. This is useful in helping catch logical errors::
|
||||
|
||||
def get_user_name(user_id: UserId) -> str:
|
||||
...
|
||||
|
||||
# typechecks
|
||||
user_a = get_user_name(UserId(42351))
|
||||
|
||||
# does not typecheck; an int is not a UserId
|
||||
user_b = get_user_name(-1)
|
||||
|
||||
You may still perform all ``int`` operations on a variable of type ``UserId``,
|
||||
but the result will always be of type ``int``. This lets you pass in a
|
||||
``UserId`` wherever an ``int`` might be expected, but will prevent you from
|
||||
accidentally creating a ``UserId`` in an invalid way::
|
||||
|
||||
# `output` is of type `int`, not `UserId`
|
||||
output = UserId(23413) + UserId(54341)
|
||||
|
||||
Note that these checks are enforced only by the static type checker. At runtime
|
||||
the statement ``Derived = NewType('Derived', Base)`` will make ``Derived`` a
|
||||
function that immediately returns whatever parameter you pass it. That means
|
||||
the expression ``Derived(some_value)`` does not create a new class or introduce
|
||||
any overhead beyond that of a regular function call.
|
||||
|
||||
More precisely, the expression ``some_value is Derived(some_value)`` is always
|
||||
true at runtime.
|
||||
|
||||
This also means that it is not possible to create a subtype of ``Derived``
|
||||
since it is an identity function at runtime, not an actual type. Similarly, it
|
||||
is not possible to create another ``NewType`` based on a ``Derived`` type::
|
||||
|
||||
from typing import NewType
|
||||
|
||||
UserId = NewType('UserId', int)
|
||||
|
||||
# Fails at runtime and does not typecheck
|
||||
class AdminUserId(UserId): pass
|
||||
|
||||
# Also does not typecheck
|
||||
ProUserId = NewType('ProUserId', UserId)
|
||||
|
||||
See :pep:`484` for more details.
|
||||
|
||||
.. note::
|
||||
|
||||
Recall that the use of a type alias declares two types to be *equivalent* to
|
||||
one another. Doing ``Alias = Original`` will make the static type checker
|
||||
treat ``Alias`` as being *exactly equivalent* to ``Original`` in all cases.
|
||||
This is useful when you want to simplify complex type signatures.
|
||||
|
||||
In contrast, ``NewType`` declares one type to be a *subtype* of another.
|
||||
Doing ``Derived = NewType('Derived', Original)`` will make the static type
|
||||
checker treat ``Derived`` as a *subclass* of ``Original``, which means a
|
||||
value of type ``Original`` cannot be used in places where a value of type
|
||||
``Derived`` is expected. This is useful when you want to prevent logic
|
||||
errors with minimal runtime cost.
|
||||
|
||||
Callable
|
||||
--------
|
||||
|
||||
|
|
Loading…
Reference in New Issue