summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2016-07-29 22:38:14 (GMT)
committerGuido van Rossum <guido@python.org>2016-07-29 22:38:14 (GMT)
commit342e800e974475cc302c46ed6d9f75276035278f (patch)
tree269226dacfb0d76600f588c0b55c960702c96add
parent1050d2d0c7730c6c533246bb2404937739a7775c (diff)
downloadcpython-342e800e974475cc302c46ed6d9f75276035278f.zip
cpython-342e800e974475cc302c46ed6d9f75276035278f.tar.gz
cpython-342e800e974475cc302c46ed6d9f75276035278f.tar.bz2
Expand documentation about type aliases and NewType in the typing module.
By Michael Lee.
-rw-r--r--Doc/library/typing.rst97
1 files changed, 96 insertions, 1 deletions
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 317229d..e11c0c2 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -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
--------