[docs] Expand documentation about type aliases and NewType in the typing module (issue 27644)

michael.lee.0x2a at gmail.com michael.lee.0x2a at gmail.com
Thu Jul 28 18:46:24 EDT 2016


Reviewers: gvanrossum, levkivskyi,


http://bugs.python.org/review/27644/diff/18004/Doc/library/typing.rst
File Doc/library/typing.rst (right):

http://bugs.python.org/review/27644/diff/18004/Doc/library/typing.rst#newcode65
Doc/library/typing.rst:65: The static type checker will treat the new
type almost as if it were a subclass
On 2016/07/29 00:11:37, levkivskyi wrote:
> It is not clear why do you need word "almost" here.
> NewType creates something that type checker treats as equivalent of a
subclass
> with only one constructor that accepts an instance of the base class.

I used the word "almost" mainly because the created type doesn't behave
exactly like a subclass in all cases -- the main difference is that
you're not allowed to subclass the derived type. So, this fails:

    from typing import NewType

    UserId = NewType('UserId', int)

    # Throws an exception at runtime; mypy explicitly flags this as an
error
    class Foo(UserId): pass

So I guess it might be more accurate to say that NewType creates
something that behaves like a final subclass, in Java terms?

Should I edit the patch to include a sentence or two describing this
distinction, just remove the word "almost", or do something else?



Please review this at http://bugs.python.org/review/27644/

Affected files:
  Doc/library/typing.rst


diff -r da9898e7e90d -r c5151efd2bca Doc/library/typing.rst
--- a/Doc/library/typing.rst	Wed Jul 27 16:59:22 2016 +0200
+++ b/Doc/library/typing.rst	Thu Jul 28 10:12:22 2016 -0700
@@ -29,10 +29,77 @@
 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]
 
+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 almost 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:
+       ...
+
+   user_a = get_user_name(UserId(42351))  # typechecks
+   user_b = get_user_name(-1)             # does not typecheck; an int is not a UserId
+
+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 = UserId(23413) + UserId(54341)  # `output` is of type `int`, not `UserId`
+
+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 == Derived(some_value)`` is always true at runtime.
+
+See :pep:`484` for more details.
+
+.. note::
+
+   Recall that type aliases 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 *derivative* 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
 --------
 




More information about the docs mailing list