[Python-checkins] peps: Update the section on type erasure to disallow Node[int]() -- you must use a

guido.van.rossum python-checkins at python.org
Mon Apr 4 20:40:51 EDT 2016


https://hg.python.org/peps/rev/1ad9e828ca36
changeset:   6275:1ad9e828ca36
user:        Guido van Rossum <guido at python.org>
date:        Mon Apr 04 17:39:26 2016 -0700
summary:
  Update the section on type erasure to disallow Node[int]() -- you must use a type alias.

files:
  pep-0484.txt |  65 +++++++++++++++++++++++++--------------
  1 files changed, 41 insertions(+), 24 deletions(-)


diff --git a/pep-0484.txt b/pep-0484.txt
--- a/pep-0484.txt
+++ b/pep-0484.txt
@@ -462,41 +462,58 @@
   class Node(Generic[T]):
       ...
 
-Now there are two ways we can instantiate this class; the type
-inferred by a type checker may be different depending on the form we
-use.  The first way is to give the value of the type parameter
-explicitly -- this overrides whatever type inference the type
-checker would otherwise perform::
+To create ``Node`` instances you call ``Node()`` just as for a regular
+class.  At runtime the type (class) of the instance will be ``Node``.
+But what type does it have to the type checker?  The answer depends on
+how much information is available in the call.  If the constructor
+(``__init__`` or ``__new__``) uses ``T`` in its signature, and a
+corresponding argument value is passed, the type of the corresponding
+argument(s) is substituted.  Otherwise, ``Any`` is assumed.  Example::
 
-  x = Node[T]()  # The type inferred for x is Node[T].
+  from typing import TypeVar, Generic
 
-  y = Node[int]()  # The type inferred for y is Node[int].
+  T = TypeVar('T')
 
-If no explicit types are given, the type checker is given some
-freedom. Consider this code::
+  class Node(Generic[T]):
+      def __init__(self, label: T = None) -> None:
+          ...
 
-  x = Node()
+  x = Node('')  # Inferred type is Node[str]
+  y = Node(0)   # Inferred type is Node[int]
+  z = Node()    # Inferred type is Node[Any]
 
-The inferred type could be ``Node[Any]``, as there isn't enough
-context to infer a more precise type.  Alternatively, a type checker
-may reject the line and require an explicit annotation, like this::
+In case the inferred type uses ``[Any]`` but the intended type is more
+specific, you can use a type comment (see below) to force the type of
+the variable, e.g.::
 
-  x = Node()  # type: Node[int]  # Inferred type is Node[int].
+  # (continued from previous example)
+  a = Node()  # type: Node[int]
+  b = Node()  # type: Node[str]
 
-A type checker with more powerful type inference could look at how
-``x`` is used elsewhere in the file and try to infer a more precise
-type such as ``Node[int]`` even without an explicit type annotation.
-However, it is probably impossible to make such type inference work
-well in all cases, since Python programs can be very dynamic.
+You can also create a type alias (see above) for a specific concrete
+type and instantiate it, e.g.::
 
-This PEP doesn't specify the details of how type inference should
-work.  We allow different tools to experiment with various approaches.
-We may give more explicit rules in future revisions.
+  # (continued from previous example)
+  IntNode = Node[int]
+  StrNode = Node[str]
+  p = IntNode()    # Inferred type is Node[str]
+  q = StrNode()    # Inferred type is Node[int]
+  r = IntNode('')  # Error
+  s = StrNode(0)   # Error
 
-At runtime the type is not preserved, and the class of ``x`` is just
-``Node`` in all cases.  This behavior is called "type erasure"; it is
+Note that the runtime type (class) of p and q is still just ``Node``
+-- ``IntNode`` and ``StrNode`` are distinguishable class objects, but
+the type (class) of the objects created by instantiating them doesn't
+record the distinction.  This behavior is called "type erasure"; it is
 common practice in languages with generics (e.g. Java, TypeScript).
 
+You cannot use the subscripted class (e.g. ``Node[int]``) directly in
+an expression -- you must define a type alias.  (This restriction
+exists because creating the subscripted class, e.g. ``Node[int]``, is
+an expensive operation -- usually many times as expensive as
+constructing an instance of it.  Using a type alias is also more
+readable.)
+
 
 Arbitrary generic types as base classes
 ---------------------------------------

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


More information about the Python-checkins mailing list