New version of PEP 484 for review by python-dev.

This commit is contained in:
Guido van Rossum 2015-04-17 14:44:03 -07:00
parent 7447d4fe83
commit 4f41b1f9e3
1 changed files with 513 additions and 183 deletions

View File

@ -3,12 +3,13 @@ Title: Type Hints
Version: $Revision$
Last-Modified: $Date$
Author: Guido van Rossum <guido@python.org>, Jukka Lehtosalo <jukka.lehtosalo@iki.fi>, Łukasz Langa <lukasz@langa.pl>
BDFL-delegate: Mark Shannon
Discussions-To: Python-Dev <python-dev@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 @@ The proposal is strongly inspired by mypy [mypy]_. For example, the
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 @@ typed language, and the authors have no desire to ever make type hints
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.)
.. 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.
Type aliases are also valid type hints::
integer = int
def retry(url: str, retry_count: integer) -> None: ...
New names that are added to support features described in following
sections are available in the ``typing`` package.
Expressions whose type is a subtype of a specific argument type are
also accepted for that argument.
Callbacks
---------
Acceptable 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).
Annotations must be valid expressions that evaluate without raising
exceptions at the time the function is defined (but see below for
forward references).
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.)
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.
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 @@ Generics can be parametrized by using a new factory available in
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 @@ When the type of a value is ``object``, the type checker will reject
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 @@ differences, simple conditionals can be used::
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 @@ Occasionally the type checker may need a different kind of hint: the
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 @@ the type of ``x`` is ``t``. At runtime a cast always returns the
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 @@ stub files:
* 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 @@ satisfactory multiple dispatch design, but we don't want such a design
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 @@ in which case the recommendation is to put this information in a
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 @@ holds a set of classes representing builtin types with generics, namely:
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 @@ generics and union types:
* 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 @@ importable from the ``typing`` package, with added generics support:
* 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 @@ The library includes literals for platform-specific type hinting:
* 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 @@ As written this will not work, because of the peculiarity in Python
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 @@ all). This of course would run afoul of backwards compatibility,
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 @@ It's also been proposed to simply wait another release. But what
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 @@ Acknowledgements
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