[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,
File Doc/library/typing.rst (right):
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
> 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
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/
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 @@
-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:
+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.
+ 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.
More information about the docs