[Python-checkins] peps: New version of PEP 484 for review by python-dev.

guido.van.rossum python-checkins at python.org
Fri Apr 17 23:44:15 CEST 2015


https://hg.python.org/peps/rev/9c4dca560aa9
changeset:   5765:9c4dca560aa9
user:        Guido van Rossum <guido at python.org>
date:        Fri Apr 17 14:44:03 2015 -0700
summary:
  New version of PEP 484 for review by python-dev.

files:
  pep-0484.txt |  684 ++++++++++++++++++++++++++++----------
  1 files changed, 507 insertions(+), 177 deletions(-)


diff --git a/pep-0484.txt b/pep-0484.txt
--- a/pep-0484.txt
+++ b/pep-0484.txt
@@ -3,12 +3,13 @@
 Version: $Revision$
 Last-Modified: $Date$
 Author: Guido van Rossum <guido at python.org>, Jukka Lehtosalo <jukka.lehtosalo at iki.fi>, Łukasz Langa <lukasz at langa.pl>
+BDFL-delegate: Mark Shannon
 Discussions-To: Python-Dev <python-dev at python.org>
 Status: Draft
 Type: Standards Track
 Content-Type: text/x-rst
 Created: 29-Sep-2014
-Post-History: 16-Jan-2015,20-Mar-2015
+Post-History: 16-Jan-2015,20-Mar-2015,17-Apr-2015
 Resolution:
 
 
@@ -33,7 +34,7 @@
 type "sequence of integers" can be written as ``Sequence[int]``.  The
 square brackets mean that no new syntax needs to be added to the
 language.  The example here uses a custom class ``Sequence``, imported
-from a pure-Python module ``typing.py``.  The ``Sequence[int]``
+from a pure-Python module ``typing``.  The ``Sequence[int]``
 notation works by implementing ``__getitem__()`` in the metaclass.
 
 The type system supports unions, generic types, and a special type
@@ -78,47 +79,134 @@
 mandatory, even by convention.
 
 
+What is checked?
+================
+
+Any function (or method -- for brevity we won't be repeating this)
+with at least one argument or return annotation is checked, unless
+type checking is disabled by the ``@no_type_check`` decorator or a
+``# type: ignore`` comment (see below).
+
+A checked function should have annotations for all its arguments and
+its return type, with the exception that the ``self`` argument of a
+method should not be annotated; it is assumed to have the type of the
+containing class.  Notably, the return type of ``__init__`` should be
+annotated with ``-> None``.
+
+The body of a checked function is checked for consistency with the
+given annotations.  The annotations are also used to check correctness
+of calls appearing in other checked functions.
+
+Functions without any annotations (or whose checking is disabled) are
+assumed to have type ``Any`` when they are referenced in checked
+functions, and this should completely silence complaints from the
+checker regarding those references (although a checker may still
+request that a type be specified using a cast or a ``# type:`` comment
+if a more specific type than ``Any`` is needed for analysis of
+subsequent code).
+
+A type checker should understand decorators; this may require
+annotations on decorator definitions.  In particular, a type checker
+should understand the built-in decorators ``@property``,
+``@staticmethod`` and ``@classmethod``.  The first argument of a class
+method should not be annotated; it is assumed to be a subclass of the
+defining class.
+
+
 Type Definition Syntax
 ======================
 
 The syntax leverages PEP 3107-style annotations with a number of
-extensions described in sections below.  In its basic form, type hinting
-is used by filling function annotations with classes::
+extensions described in sections below.  In its basic form, type
+hinting is used by filling function annotation slots with classes::
 
   def greeting(name: str) -> str:
       return 'Hello ' + name
 
-This denotes that the expected type of the ``name`` argument is ``str``.
-Analogically, the expected return type is ``str``.  Subclasses of
-a specified argument type are also accepted as valid types for that
-argument.
+This states that the expected type of the ``name`` argument is
+``str``.  Analogically, the expected return type is ``str``.
 
-Abstract base classes, types available in the ``types`` module, and
-user-defined classes may be used as type hints as well.  Annotations
-must be valid expressions that evaluate without raising exceptions at
-the time the function is defined.  In addition, the needs of static
-analysis require that annotations must be simple enough to be
-interpreted by static analysis tools.  (This is an intentionally
-somewhat vague requirement.)
+Expressions whose type is a subtype of a specific argument type are
+also accepted for that argument.
 
-.. FIXME: Define rigorously what is/isn't supported.
 
-When used as an annotation, the expression ``None`` is considered
-equivalent to ``NoneType`` (i.e., ``type(None)`` for type hinting
-purposes.
+Acceptable type hints
+---------------------
 
-Type aliases are also valid type hints::
+Type hints may be built-in classes (including those defined in
+standard library or third-party extension modules), abstract base
+classes, types available in the ``types`` module, and user-defined
+classes (including those defined in the standard library or
+third-party modules).  Annotations for built-in classes (and other
+classes at the discretion of the developer) may be placed in stub
+files (see below).
 
-  integer = int
+Annotations must be valid expressions that evaluate without raising
+exceptions at the time the function is defined (but see below for
+forward references).
 
-  def retry(url: str, retry_count: integer) -> None: ...
+The needs of static analysis require that annotations must be simple
+enough to be interpreted by static analysis tools.  In particular,
+dynamically computed types are not acceptable.  (This is an
+intentionally somewhat vague requirement, specific inclusions and
+exclusions may be added to future versions of this PEP as warranted by
+the discussion.)
 
-New names that are added to support features described in following
-sections are available in the ``typing`` package.
+In addition to the above, the following special constructs defined
+below may be used: ``None``, ``Any``, ``Union``, ``Tuple``,
+``Callable``, all ABCs and stand-ins for concrete classes exported
+from ``typing`` (e.g. ``Sequence`` and ``Dict``), type variables, and
+type aliases.
 
+All newly introducedw names used to support features described in
+following sections (such as ``Any`` and ``Union``) are available in
+the ``typing`` module.
 
-Callbacks
----------
+
+Using None
+----------
+
+When used in a type hint, the expression ``None`` is considered
+equivalent to ``type(None)``.
+
+
+Type aliases
+------------
+
+Type aliases are defined by simple variable assignments::
+
+  Url = str
+
+  def retry(url: Url, retry_count: int) -> None: ...
+
+Note that we recommend capitalizing alias names, since they represent
+user-defined types, which (like user-defined classes) are typically
+spelled that way.
+
+Type aliases may be as complex as type hints in annotations --
+anything that is acceptable as a type hint is acceptable in a type
+alias::
+
+    from typing import TypeVar, Iterable, Tuple
+
+    T = TypeVar('T', int, float, complex)
+    Vector = Iterable[Tuple[T, T]]
+
+    def inproduct(v: Vector) -> T:
+        return sum(x*y for x, y in v)
+
+This is equivalent to::
+
+    from typing import TypeVar, Iterable, Tuple
+
+    T = TypeVar('T', int, float, complex)
+
+    def inproduct(v: Iterable[Tuple[T, T]]) -> T:
+        return sum(x*y for x, y in v)
+
+
+Callable
+--------
 
 Frameworks expecting callback functions of specific signatures might be
 type hinted using ``Callable[[Arg1Type, Arg2Type], ReturnType]``.
@@ -173,44 +261,217 @@
   def first(l: Sequence[T]) -> T:   # Generic function
       return l[0]
 
-In this case the contract is that the returning value is consistent with
+In this case the contract is that the returned value is consistent with
 the elements held by the collection.
 
-``TypeVar`` supports constraining parametric types to classes with any of
-the specified bases.  Example::
+``TypeVar`` supports constraining parametric types to a fixed set of
+possible types.  For example, we can define a type variable that ranges
+over just ``str`` and ``bytes``.  By default, a type variable ranges
+over all possible types.  Example of constraining a type variable::
+
+  from typing import TypeVar
+
+  AnyStr = TypeVar('AnyStr', str, bytes)
+
+  def concat(x: AnyStr, y: AnyStr) -> AnyStr:
+      return x + y
+
+The function ``concat`` can be called with either two ``str`` arguments
+or two ``bytes`` arguments, but not with a mix of ``str`` and ``bytes``
+arguments.
+
+Note that subtypes of types constrained by a type variable are treated
+as their respective explicitly listed base types in the context of the
+type variable.  Consider this example::
+
+  class MyStr(str): ...
+
+  x = concat(MyStr('apple'), MyStr('pie'))
+
+The call is valid but the type variable ``AnyStr`` will be set to
+``str`` and not ``MyStr``. In effect, the inferred type of the return
+value assigned to ``x`` will also be ``str``.
+
+Additionally, ``Any`` is a valid value for every type variable.
+Consider the following::
+
+  def count_truthy(elements: List[Any]) -> int:
+      return sum(1 for elem in elements if element)
+
+This is equivalent to omitting the generic notation and just saying
+``elements: List``.
+
+
+User-defined generic types
+--------------------------
+
+You can include a ``Generic`` base class to define a user-defined class
+as generic.  Example::
+
+  from typing import TypeVar, Generic
+
+  T = TypeVar('T')
+
+  class LoggedVar(Generic[T]):
+      def __init__(self, value: T, name: str, logger: Logger) -> None:
+          self.name = name
+          self.logger = logger
+          self.value = value
+
+      def set(self, new: T) -> None:
+          self.log('Set ' + repr(self.value))
+          self.value = new
+
+      def get(self) -> T:
+          self.log('Get ' + repr(self.value))
+          return self.value
+
+      def log(self, message: str) -> None:
+          self.logger.info('{}: {}'.format(self.name message))
+
+``Generic[T]`` as a base class defines that the class ``LoggedVar``
+takes a single type parameter ``T``. This also makes ``T`` valid as
+a type within the class body.
+
+The ``Generic`` base class uses a metaclass that defines ``__getitem__``
+so that ``LoggedVar[t]`` is valid as a type::
 
   from typing import Iterable
 
-  X = TypeVar('X')
-  Y = TypeVar('Y', Iterable[X])
+  def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
+      for var in vars:
+          var.set(0)
 
-  def filter(rule: Callable[[X], bool], input: Y) -> Y:
+A generic type can have any number of type variables, and type variables
+may be constrained. This is valid::
+
+  from typing import TypeVar, Generic
+  ...
+
+  T = TypeVar('T')
+  S = TypeVar('S')
+
+  class Pair(Generic[T, S]):
       ...
 
-.. FIXME: Add an example with multiple bases defined.
+Each type variable argument to ``Generic`` must be distinct. This is
+thus invalid::
 
-In the example above we specify that ``Y`` can be any subclass of
-Iterable with elements of type ``X``, as long as the return type of
-``filter()`` will be the same as the type of the ``input``
-argument.
+  from typing import TypeVar, Generic
+  ...
 
-.. FIXME: Explain more about how this works.
+  T = TypeVar('T')
+
+  class Pair(Generic[T, T]):   # INVALID
+      ...
+
+You can use multiple inheritance with ``Generic``::
+
+  from typing import TypeVar, Generic, Sized
+
+  T = TypeVar('T')
+
+  class LinkedList(Sized, Generic[T]):
+      ...
+
+
+Arbitrary generic types as base classes
+---------------------------------------
+
+``Generic[T]`` is only valid as a base class -- it's not a proper type.
+However, user-defined generic types such as ``LinkedList[T]`` from the
+above example and built-in generic types and ABCs such as ``List[T]``
+and ``Iterable[T]`` are valid both as types and as base classes. For
+example, we can define a subclass of ``Dict`` that specializes type
+arguments::
+
+  from typing import Dict, List, Optional
+
+  class Node:
+      ...
+
+  class SymbolTable(Dict[str, List[Node]]):
+      def push(self, name: str, node: Node) -> None:
+          self.setdefault(name, []).append(node)
+
+      def pop(self, name: str) -> Node:
+          return self[name].pop()
+
+      def lookup(self, name: str) -> Optional[Node]:
+          nodes = self.get(name)
+          if nodes:
+              return nodes[-1]
+          return None
+
+``SymbolTable`` is a subclass of ``dict`` and a subtype of ``Dict[str,
+List[Node]]``.
+
+If a generic base class has a type variable as a type argument, this
+makes the defined class generic. For example, we can define a generic
+``LinkedList`` class that is iterable and a container::
+
+  from typing import TypeVar, Iterable, Container
+
+  T = TypeVar('T')
+
+  class LinkedList(Iterable[T], Container[T]):
+      ...
+
+Now ``LinkedList[int]`` is a valid type. Note that we can use ``T``
+multiple times in the base class list, as long as we don't use the
+same type variable ``T`` multiple times within ``Generic[...]``.
+
+
+Abstract generic types
+----------------------
+
+The metaclass used by ``Generic`` is a subclass of ``abc.ABCMeta``.
+A generic class can be an ABC by including abstract methods
+or properties, and generic classes can also have ABCs as base
+classes without a metaclass conflict.
 
 
 Forward references
 ------------------
 
 When a type hint contains names that have not been defined yet, that
-definition may be expressed as a string, to be resolved later.  For
-example, instead of writing::
+definition may be expressed as a string literal, to be resolved later.
 
-  def notify_by_email(employees: Set[Employee]) -> None: ...
+A situation where this occurs commonly is the definition of a
+container class, where the class being defined occurs in the signature
+of some of the methods.  For example, the following code (the start of
+a simple binary tree implementation) does not work::
 
-one might write::
+  class Tree:
+      def __init__(self, left: Tree, right: Tree):
+          self.left = left
+          self.right = right
 
-  def notify_by_email(employees: 'Set[Employee]') -> None: ...
+To address this, we write::
 
-.. FIXME: Rigorously define this, and give a motivational example.
+  class Tree:
+      def __init__(self, left: 'Tree', right: 'Tree'):
+          self.left = left
+          self.right = right
+
+The string literal should contain a valid Python expression (i.e.,
+``compile(lit, '', 'expr')`` should be a valid code object) and it
+should evaluate without errors once the module has been fully loaded.
+The local and global namespace in which it is evaluated should be the
+same namespaces in which default arguments to the same function would
+be evaluated.
+
+Moreover, the expression should be parseable as a valid type hint, i.e.,
+it is constrained by the rules from the section `Acceptable type hints`_
+above.
+
+It is allowable to use string literals as *part* of a type hint, for
+example::
+
+    class Tree:
+        ...
+        def leaves(self) -> List['Tree']:
+            ...
 
 
 Union types
@@ -264,18 +525,17 @@
 almost all operations on it, and assigning it to a variable (or using
 it as a return value) of a more specialized type is a type error.  On
 the other hand, when a value has type ``Any``, the type checker will
-allow all operations on it, and a value of type `Any`` can be assigned
+allow all operations on it, and a value of type ``Any`` can be assigned
 to a variable (or used as a return value) of a more constrained type.
 
 
-Platform-specific type checking
--------------------------------
+Predefined constants
+--------------------
 
-In some cases the typing information will depend on the platform that
-the program is being executed on.  To enable specifying those
-differences, simple conditionals can be used::
+Some predefined Boolean constants are defined in the ``typing``
+module to enable platform-specific type definitions and such::
 
-  from typing import PY2, WINDOWS
+  from typing import PY2, PY3, WINDOWS, POSIX
 
   if PY2:
       text = unicode
@@ -289,66 +549,82 @@
   else:
       loop = UnixSelectorEventLoop
 
-.. FIXME: Also define PY3 and POSIX?
-
-Arbitrary literals defined in the form of ``NAME = True`` will also be
-accepted by the type checker to differentiate type resolution::
-
-  DEBUG = False
-  ...
-  if DEBUG:
-      class Tracer:
-          <verbose implementation>
-  else:
-      class Tracer:
-          <dummy implementation>
-
-For the purposes of type hinting, the type checker assumes ``__debug__``
-is set to ``True``, in other words the ``-O`` command-line option is not
-used while type checking.
+It is up to the type checker implementation to define their values, as
+long as ``PY2 == not PY3`` and ``WINDOWS == not POSIX``.  When the
+program is being executed these always reflect the current platform,
+and this is also the suggested default when the program is being
+type-checked.
 
 
 Compatibility with other uses of function annotations
------------------------------------------------------
+=====================================================
 
 A number of existing or potential use cases for function annotations
-exist, which are incompatible with type hinting.  These may confuse a
-static type checker.  However, since type hinting annotations have no
-runtime behavior (other than evaluation of the annotation expression
-and storing annotations in the ``__annotations__`` attribute of the
-function object), this does not make the program incorrect -- it just
-makes it issue warnings when a static analyzer is used.
+exist, which are incompatible with type hinting.  These may confuse
+a static type checker.  However, since type hinting annotations have no
+runtime behavior (other than evaluation of the annotation expression and
+storing annotations in the ``__annotations__`` attribute of the function
+object), this does not make the program incorrect -- it just may cause
+a type checker to emit spurious warnings or errors.
 
 To mark portions of the program that should not be covered by type
-hinting, use the following:
+hinting, you can use one or more of the following:
 
-* a ``@no_type_check`` decorator on classes and functions
+* a ``# type: ignore`` comment;
 
-* a ``# type: ignore`` comment on arbitrary lines
+* a ``@no_type_check`` decorator on a class or function;
 
-.. FIXME: should we have a module-wide comment as well?
+* a custom class or function decorator marked with
+  ``@no_type_check_decorator``.
 
-.. FIXME: suggest that other uses of annotations be replaced with decorators
+For more details see later sections.
 
-.. FIXME: add reference to "rejected alternatives"
+In order for maximal compatibility with offline type checking it may
+eventually be a good idea to change interfaces that rely on annotations
+to switch to a different mechanism, for example a decorator.  In Python
+3.5 there is no pressure to do this, however.  See also the longer
+discussion under `Rejected alternatives`_ below.
 
 
-Type Hints on Local and Global Variables
-========================================
+Type comments
+=============
 
 No first-class syntax support for explicitly marking variables as being
 of a specific type is added by this PEP.  To help with type inference in
 complex cases, a comment of the following format may be used::
 
   x = []   # type: List[Employee]
+  x, y, z = [], [], []  # type: List[int], List[int], List[str]
+  x, y, z = [], [], []  # type: (List[int], List[int], List[str])
+  x = [
+     1,
+     2,
+  ]  # type: List[int]
 
-In the case where type information for a local variable is needed before
-it is declared, an ``Undefined`` placeholder might be used::
+Type comments should be put on the last line of the statement that
+contains the variable definition. They can also be placed on
+``with`` statements and ``for`` statements, right after the colon.
 
-  from typing import Undefined
+Examples of type comments on ``with`` and ``for`` statements::
 
-  x = Undefined   # type: List[Employee]
-  y = Undefined(int)
+  with frobnicate() as foo:  # type: int
+      # Here foo is an int
+      ...
+
+  for x, y in points:  # type: float, float
+      # Here x and y are floats
+      ...
+
+The ``# type: ignore`` comment should be put on the line that the
+error refers to::
+
+  import http.client
+  errors = {
+      'not_found': http.client.NOT_FOUND  # type: ignore
+  }
+
+A ``# type: ignore`` comment on a line by itself disables all type
+checking for the rest of the file.
 
 If type hinting proves useful in general, a syntax for typing variables
 may be provided in a future Python version.
@@ -360,7 +636,7 @@
 programmer may know that an expression is of a more constrained type
 than the type checker infers.  For example::
 
-  from typing import List
+  from typing import List, cast
 
   def find_first_str(a: List[object]) -> str:
       index = next(i for i, x in enumerate(a) if isinstance(x, str))
@@ -374,11 +650,11 @@
 expression unchanged -- it does not check the type, and it does not
 convert or coerce the value.
 
-Casts differ from type comments (see the previous section).  When
-using a type comment, the type checker should still verify that the
-inferred type is consistent with the stated type.  When using a cast,
-the type checker trusts the programmer.  Also, casts can be used in
-expressions, while type comments only apply to assignments.
+Casts differ from type comments (see the previous section).  When using
+a type comment, the type checker should still verify that the inferred
+type is consistent with the stated type.  When using a cast, the type
+checker should blindly believe the programmer.  Also, casts can be used
+in expressions, while type comments only apply to assignments.
 
 
 Stub Files
@@ -390,28 +666,31 @@
 
 * Extension modules
 
-* 3rd party modules whose authors have not yet added type hints
+* Third-party modules whose authors have not yet added type hints
 
-* Standard library modules for which type hints have not yet been written
+* Standard library modules for which type hints have not yet been
+  written
 
 * Modules that must be compatible with Python 2 and 3
 
 * Modules that use annotations for other purposes
 
-Stub files have the same syntax as regular Python modules.  There is
-one feature of the ``typing`` module that may only be used in stub
-files: the ``@overload`` decorator described below.
+Stub files have the same syntax as regular Python modules.  There is one
+feature of the ``typing`` module that may only be used in stub files:
+the ``@overload`` decorator described below.
 
 The type checker should only check function signatures in stub files;
-function bodies in stub files should just be a single ``pass`` statement.
+function bodies in stub files should just be a single ``pass``
+statement.
 
-The type checker should have a configurable search path for stub
-files.  If a stub file is found the type checker should not read the
+The type checker should have a configurable search path for stub files.
+If a stub file is found the type checker should not read the
 corresponding "real" module.
 
-Stub files may use the ``.py`` extension or alternatively may use the
-``.pyi`` extension.  The latter makes it possible to maintain stub
-files in the same directory as the corresponding real module.
+While stub files are syntactically valid Python modules, they use the
+``.pyi`` extension to make it possible to maintain stub files in the
+same directory as the corresponding real module.  This also reinforces
+the notion that no runtime behavior should be expected of stub files.
 
 Function overloading
 --------------------
@@ -478,6 +757,54 @@
 to be constrained by the overloading syntax defined for type hints in
 stub files.
 
+Storing and distributing stub files
+-----------------------------------
+
+The easiest form of stub file storage and distribution is to put them
+alongside Python modules in the same directory.  This makes them easy to
+find by both programmers and the tools.  However, since package
+maintainers are free not to add type hinting to their packages,
+third-party stubs installable by ``pip`` from PyPI are also supported.
+In this case we have to consider three issues: naming, versioning,
+installation path.
+
+This PEP does not provide a recommendation on a naming scheme that
+should be used for third-party stub file packages.  Discoverability will
+hopefully be based on package popularity, like with Django packages for
+example.
+
+Third-party stubs have to be versioned using the lowest version of the
+source package that is compatible.  Example: FooPackage has versions
+1.0, 1.1, 1.2, 1.3, 2.0, 2.1, 2.2.  There are API changes in versions
+1.1, 2.0 and 2.2.  The stub file package maintainer is free to release
+stubs for all versions but at least 1.0, 1.1, 2.0 and 2.2 are needed
+to enable the end user type check all versions.  This is because the
+user knows that the closest *lower or equal* version of stubs is
+compatible.  In the provided example, for FooPackage 1.3 the user would
+choose stubs version 1.1.
+
+Note that if the user decides to use the "latest" available source
+package, using the "latest" stub files should generally also work if
+they're updated often.
+
+Third-party stub packages can use any location for stub storage.  The
+type checker will search for them using PYTHONPATH.  A default fallback
+directory that is always checked is ``shared/typehints/python3.5/`` (or
+3.6, etc.).  Since there can only be one package installed for a given
+Python version per environment, no additional versioning is performed
+under that directory (just like bare directory installs by ``pip`` in
+site-packages).  Stub file package authors might use the following
+snippet in ``setup.py``::
+
+  ...
+  data_files=[
+      (
+          'shared/typehints/python{}.{}'.format(*sys.version_info[:2]),
+          pathlib.Path(SRC_PATH).glob('**/*.pyi'),
+      ),
+  ],
+  ...
+
 
 Exceptions
 ==========
@@ -488,12 +815,12 @@
 docstring.
 
 
-The ``typing`` Package
-======================
+The ``typing`` Module
+=====================
 
 To open the usage of static type checking to Python 3.5 as well as older
 versions, a uniform namespace is required.  For this purpose, a new
-package in the standard library is introduced called ``typing``.  It
+module in the standard library is introduced called ``typing``.  It
 holds a set of classes representing builtin types with generics, namely:
 
 * Dict, used as ``Dict[key_type, value_type]``
@@ -511,12 +838,24 @@
   using one type and ellipsis, for example ``Tuple[int, ...]``.
   (The ``...`` here are part of the syntax.)
 
+* NamedTuple, used as
+  ``NamedTuple(type_name, [(field_name, field_type), ...])``
+  and equivalent to
+  ``collections.namedtuple(type_name, [field_name, ...])``.
+
 The generic versions of concrete collection types (``Dict``, ``List``,
 ``Set``, ``FrozenSet``, and homogeneous arbitrary-length ``Tuple``)
 are mainly useful for annotating return values.  For arguments, prefer
 the abstract collection types defined below, e.g.  ``Mapping``,
 ``Sequence`` or ``AbstractSet``.
 
+The ``typing`` module defines the ``Generator`` type for return values
+of generator functions. It is a subtype of ``Iterable`` and it has
+additional type variables for the type accepted by the ``send()``
+method and the return type of the generator:
+
+* Generator, used as ``Generator[yield_type, send_type, return_type]``
+
 It also introduces factories and helper members needed to express
 generics and union types:
 
@@ -527,24 +866,20 @@
 * TypeVar, used as ``X = TypeVar('X', Type1, Type2, Type3)`` or simply
   ``Y = TypeVar('Y')``
 
-* Undefined, used as ``local_variable = Undefined # type: List[int]`` or
-  ``local_variable = Undefined(List[int])`` (the latter being slower
-  during runtime)
-
 * Callable, used as ``Callable[[Arg1Type, Arg2Type], ReturnType]``
 
-* AnyStr, equivalent to ``TypeVar('AnyStr', str, bytes)``
+* AnyStr, defined as ``TypeVar('AnyStr', str, bytes)``
 
 All abstract base classes available in ``collections.abc`` are
-importable from the ``typing`` package, with added generics support:
+importable from the ``typing`` module, with added generics support:
 
 * ByteString
 
-* Callable
+* Callable (see above)
 
 * Container
 
-* Hashable
+* Hashable (not generic, but present for completeness)
 
 * ItemsView
 
@@ -566,14 +901,26 @@
 
 * Sequence
 
-* Set as ``AbstractSet``. This name change was required because ``Set``
-  in the ``typing`` module means ``set()`` with generics.
+* Set, renamed to ``AbstractSet``. This name change was required
+  because ``Set`` in the ``typing`` module means ``set()`` with
+  generics.
 
-* Sized
+* Sized (not generic, but present for completeness)
 
 * ValuesView
 
-* Mapping
+A few one-off types are defined that test for single special methods
+(similar to ``Hashable`` or ``Sized``):
+
+* Reversible, to test for ``__reversed__``
+
+* SupportsAbs, to test for ``__abs__``
+
+* SupportsFloat, to test for ``__float__``
+
+* SupportsInt, to test for ``__int__``
+
+* SupportsRound, to test for ``__round__``
 
 The library includes literals for platform-specific type hinting:
 
@@ -585,55 +932,42 @@
 
 * POSIX, equivalent to ``not WINDOWS``
 
+The following conveniece functions and decorators are exported:
+
+* cast, described earlier
+
+* no_type_check, a decorator to disable type checking per class or
+  function (see below)
+
+* no_type_check_decorator, a decorator to create your own decorators
+  with the same meaning as ``@no_type_check`` (see below)
+
+* overload, described earlier
+
+* get_type_hints, a utility function to retrieve the type hints from a
+  function or method.  Given a function or method object, it returns
+  a dict with the same format as ``__annotations__``, but evaluating
+  forward references (which are given as string literals) as expressions
+  in the context of the original function or method definition.
+
 The following types are available in the ``typing.io`` module:
 
-* IO
+* IO (generic over ``AnyStr``)
 
-* BinaryIO
+* BinaryIO (a simple subclass of ``IO[bytes]``)
 
-* TextIO
+* TextIO (a simple subclass of ``IO[str]``)
 
 The following types are provided by the ``typing.re`` module:
 
 * Match and Pattern, types of ``re.match()`` and ``re.compile()``
-  results
+  results (generic over ``AnyStr``)
 
 As a convenience measure, types from ``typing.io`` and ``typing.re`` are
 also available in ``typing`` (quoting Guido, "There's a reason those
 modules have two-letter names.").
 
 
-The place of the ``typing`` module in the standard library
-----------------------------------------------------------
-
-.. FIXME: complete this section (or discard?)
-
-
-Usage Patterns
-==============
-
-The main use case of type hinting is static analysis using an external
-tool without executing the analyzed program.  Existing tools used for
-that purpose like ``pyflakes`` [pyflakes]_ or ``pylint`` [pylint]_
-might be extended to support type checking.  New tools, like mypy [mypy]_,
-can be adopted specifically for this purpose.
-
-Type checking based on type hints is understood as a best-effort
-mechanism.  In other words, whenever types are not annotated and cannot
-be inferred, the type checker considers such code valid.  Type errors
-are only reported in case of explicit or inferred conflict.  Moreover,
-as a mechanism that is not tied to execution of the code, it does not
-affect runtime behaviour.  In other words, even in the case of a typing
-error, the program will continue running.
-
-The implementation of a type checker, whether linting source files or
-enforcing type information during runtime, is out of scope for this PEP.
-
-.. FIXME: This is somewhat redundant with the updated initial sections.
-
-.. FIXME: Describe run-time behavior of generic types.
-
-
 Rejected Alternatives
 =====================
 
@@ -771,7 +1105,7 @@
 that class names become defined once the entire body of the class has
 been executed.  Our solution, which isn't particularly elegant, but
 gets the job done, is to allow using string literals in annotations.
-Most of the time you won't have to use this though -- most _uses_ of
+Most of the time you won't have to use this though -- most *uses* of
 type hints are expected to reference builtin types or types defined in
 other modules.
 
@@ -782,6 +1116,21 @@
 since the Python interpreter doesn't actually know whether a
 particular annotation is meant to be a type hint or something else.
 
+A compromise is possible where a ``__future__`` import could enable
+turning *all* annotations in a given module into string literals, as
+follows::
+
+  from __future__ import annotations
+
+  class ImSet:
+      def add(self, a: ImSet) -> List[ImSet]: ...
+
+  assert ImSet.add.__annotations__ == {'a': 'ImSet', 'return': 'List[ImSet]'}
+
+Such a ``__future__`` import statement will be proposed in a separate
+PEP.
+
+
 The double colon
 ----------------
 
@@ -864,26 +1213,6 @@
 problem would that solve?  It would just be procrastination.
 
 
-Is Type Hinting Pythonic?
-=========================
-
-.. FIXME: Do we really need this section?
-
-Type annotations provide important documentation for how a unit of code
-should be used.  Programmers should therefore provide type hints on
-public APIs, namely argument and return types on functions and methods
-considered public.  However, because types of local and global variables
-can be often inferred, they are rarely necessary.
-
-The kind of information that type hints hold has always been possible to
-achieve by means of docstrings.  In fact, a number of formalized
-mini-languages for describing accepted arguments have evolved.  Moving
-this information to the function declaration makes it more visible and
-easier to access both at runtime and by static analysis.  Adding to that
-the notion that “explicit is better than implicit”, type hints are
-indeed *Pythonic*.
-
-
 PEP Development Process
 =======================
 
@@ -901,7 +1230,8 @@
 
 This document could not be completed without valuable input,
 encouragement and advice from Jim Baker, Jeremy Siek, Michael Matson
-Vitousek, Andrey Vlasovskikh, and Radomir Dopieralski.
+Vitousek, Andrey Vlasovskikh, Radomir Dopieralski, Peter Ludemann,
+and the BDFL-Delegate, Mark Shannon.
 
 Influences include existing languages, libraries and frameworks
 mentioned in PEP 482.  Many thanks to their creators, in alphabetical

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


More information about the Python-checkins mailing list