[Python-checkins] cpython (merge 3.5 -> default): Expand documentation about type aliases and NewType in the typing module (merge

guido.van.rossum python-checkins at python.org
Fri Jul 29 18:41:47 EDT 2016


https://hg.python.org/cpython/rev/15a35a8da24b
changeset:   102485:15a35a8da24b
parent:      102483:ea99e2f0b829
parent:      102484:fd0dce6d33e7
user:        Guido van Rossum <guido at dropbox.com>
date:        Fri Jul 29 15:39:36 2016 -0700
summary:
  Expand documentation about type aliases and NewType in the typing module (merge 3.5 -> 3.6).

By Michael Lee.

files:
  Doc/library/typing.rst |  97 +++++++++++++++++++++++++++++-
  1 files changed, 96 insertions(+), 1 deletions(-)


diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -29,10 +29,105 @@
 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
 --------
 

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list