<div dir="ltr"><div><div>Another draft. This is mostly a bunch of clarifications and minor edits, but it also removes the four version/platform constants (PY2, PY3, WINDOWS, POSIX) in favor of asking type checkers to recognize common version checks e.g. using sys.version_info or sys.platform. This time I think the new version *will* appear on <a href="http://python.org">python.org</a>. For more frequent updates, watch <a href="https://github.com/ambv/typehinting">https://github.com/ambv/typehinting</a> .<br><br></div>Also note: I'm probably going to commit the typing.py module to the CPython repo optimistically, while Mark is still pondering his decision. Off-list he's told me he's happy with the PEP. I have to make some changes to typing.py to satisfy him; I won't have time to work on those this afternoon, and I don't want to miss (or hold up) Larry's tagging of the tree for beta 1. So a few things may end up as bugs in the issue tracker (<a href="https://github.com/ambv/typehinting/issues">https://github.com/ambv/typehinting/issues</a>) and I'll rectify those before beta 2.<br></div><div><br></div>--Guido<br><div><div><div><div class="gmail_extra"><br>PEP: 484<br>Title: Type Hints<br>Version: $Revision$<br>Last-Modified: $Date$<br>Author: Guido van Rossum <<a href="mailto:guido@python.org">guido@python.org</a>>, Jukka Lehtosalo <<a href="mailto:jukka.lehtosalo@iki.fi">jukka.lehtosalo@iki.fi</a>>, Łukasz Langa <<a href="mailto:lukasz@langa.pl">lukasz@langa.pl</a>><br>BDFL-Delegate: Mark Shannon<br>Discussions-To: Python-Dev <<a href="mailto:python-dev@python.org">python-dev@python.org</a>><br>Status: Draft<br>Type: Standards Track<br>Content-Type: text/x-rst<br>Created: 29-Sep-2014<br>Post-History: 16-Jan-2015,20-Mar-2015,17-Apr-2015,20-May-2015,22-May-2015<br>Resolution:<br><br><br>Abstract<br>========<br><br>PEP 3107 introduced syntax for function annotations, but the semantics<br>were deliberately left undefined. There has now been enough 3rd party<br>usage for static type analysis that the community would benefit from<br>a standard vocabulary and baseline tools within the standard library.<br><br>This PEP introduces a provisional module to provide these standard<br>definitions and tools, along with some conventions for situations<br>where annotations are not available.<br><br>Note that this PEP still explicitly does NOT prevent other uses of<br>annotations, nor does it require (or forbid) any particular processing<br>of annotations, even when they conform to this specification. It<br>simply enables better coordination, as PEP 333 did for web frameworks.<br><br>For example, here is a simple function whose argument and return type<br>are declared in the annotations::<br><br> def greeting(name: str) -> str:<br> return 'Hello ' + name<br><br>While these annotations are available at runtime through the usual<br>``__annotations__`` attribute, *no type checking happens at runtime*.<br>Instead, the proposal assumes the existence of a separate off-line<br>type checker which users can run over their source code voluntarily.<br>Essentially, such a type checker acts as a very powerful linter.<br>(While it would of course be possible for individual users to employ<br>a similar checker at run time for Design By Contract enforcement or<br>JIT optimization, those tools are not yet as mature.)<br><br>The proposal is strongly inspired by mypy [mypy]_. For example, the<br>type "sequence of integers" can be written as ``Sequence[int]``. The<br>square brackets mean that no new syntax needs to be added to the<br>language. The example here uses a custom type ``Sequence``, imported<br>from a pure-Python module ``typing``. The ``Sequence[int]`` notation<br>works at runtime by implementing ``__getitem__()`` in the metaclass<br>(but its significance is primarily to an offline type checker).<br><br>The type system supports unions, generic types, and a special type<br>named ``Any`` which is consistent with (i.e. assignable to and from) all<br>types. This latter feature is taken from the idea of gradual typing.<br>Gradual typing and the full type system are explained in PEP 483.<br><br>Other approaches from which we have borrowed or to which ours can be<br>compared and contrasted are described in PEP 482.<br><br><br>Rationale and Goals<br>===================<br><br>PEP 3107 added support for arbitrary annotations on parts of a<br>function definition. Although no meaning was assigned to annotations<br>then, there has always been an implicit goal to use them for type<br>hinting [gvr-artima]_, which is listed as the first possible use case<br>in said PEP.<br><br>This PEP aims to provide a standard syntax for type annotations,<br>opening up Python code to easier static analysis and refactoring,<br>potential runtime type checking, and (perhaps, in some contexts)<br>code generation utilizing type information.<br><br>Of these goals, static analysis is the most important. This includes<br>support for off-line type checkers such as mypy, as well as providing<br>a standard notation that can be used by IDEs for code completion and<br>refactoring.<br><br>Non-goals<br>---------<br><br>While the proposed typing module will contain some building blocks for<br>runtime type checking -- in particular a useful ``isinstance()``<br>implementation -- third party packages would have to be developed to<br>implement specific runtime type checking functionality, for example<br>using decorators or metaclasses. Using type hints for performance<br>optimizations is left as an exercise for the reader.<br><br>It should also be emphasized that **Python will remain a dynamically<br>typed language, and the authors have no desire to ever make type hints<br>mandatory, even by convention.**<br><br><br>The meaning of annotations<br>==========================<br><br>Any function without annotations should be treated as having the most<br>general type possible, or ignored, by any type checker. Functions<br>with the ``@no_type_check`` decorator or with a ``# type: ignore``<br>comment should be treated as having no annotations.<br><br>It is recommended but not required that checked functions have<br>annotations for all arguments and the return type. For a checked<br>function, the default annotation for arguments and for the return type<br>is ``Any``. An exception is that the first argument of instance and<br>class methods does not need to be annotated; it is assumed to have the<br>type of the containing class for instance methods, and a type object<br>type corresponding to the containing class object for class methods.<br>For example, in class ``A`` the first argument of an instance method<br>has the implicit type ``A``. In a class method, the precise type of<br>the first argument cannot be represented using the available type<br>notation.<br><br>(Note that the return type of ``__init__`` ought to be annotated with<br>``-> None``. The reason for this is subtle. If ``__init__`` assumed<br>a return annotation of ``-> None``, would that mean that an<br>argument-less, un-annotated ``__init__`` method should still be<br>type-checked? Rather than leaving this ambiguous or introducing an<br>exception to the exception, we simply say that ``__init__`` ought to<br>have a return annotation; the default behavior is thus the same as for<br>other methods.)<br><br>A type checker is expected to check the body of a checked function for<br>consistency with the given annotations. The annotations may also used<br>to check correctness of calls appearing in other checked functions.<br><br>Type checkers are expected to attempt to infer as much information as<br>necessary. The minimum requirement is to handle the builtin<br>decorators ``@property``, ``@staticmethod`` and ``@classmethod``.<br><br><br>Type Definition Syntax<br>======================<br><br>The syntax leverages PEP 3107-style annotations with a number of<br>extensions described in sections below. In its basic form, type<br>hinting is used by filling function annotation slots with classes::<br><br> def greeting(name: str) -> str:<br> return 'Hello ' + name<br><br>This states that the expected type of the ``name`` argument is<br>``str``. Analogically, the expected return type is ``str``.<br><br>Expressions whose type is a subtype of a specific argument type are<br>also accepted for that argument.<br><br><br>Acceptable type hints<br>---------------------<br><br>Type hints may be built-in classes (including those defined in<br>standard library or third-party extension modules), abstract base<br>classes, types available in the ``types`` module, and user-defined<br>classes (including those defined in the standard library or<br>third-party modules).<br><br>While annotations are normally the best format for type hints,<br>there are times when it is more appropriate to represent them<br>by a special comment, or in a separately distributed stub<br>file. (See below for examples.)<br><br>Annotations must be valid expressions that evaluate without raising<br>exceptions at the time the function is defined (but see below for<br>forward references).<br><br>Annotations should be kept simple or static analysis tools may not be<br>able to interpret the values. For example, dynamically computed types<br>are unlikely to be understood. (This is an<br>intentionally somewhat vague requirement, specific inclusions and<br>exclusions may be added to future versions of this PEP as warranted by<br>the discussion.)<br><br>In addition to the above, the following special constructs defined<br>below may be used: ``None``, ``Any``, ``Union``, ``Tuple``,<br>``Callable``, all ABCs and stand-ins for concrete classes exported<br>from ``typing`` (e.g. ``Sequence`` and ``Dict``), type variables, and<br>type aliases.<br><br>All newly introduced names used to support features described in<br>following sections (such as ``Any`` and ``Union``) are available in<br>the ``typing`` module.<br><br><br>Using None<br>----------<br><br>When used in a type hint, the expression ``None`` is considered<br>equivalent to ``type(None)``.<br><br><br>Type aliases<br>------------<br><br>Type aliases are defined by simple variable assignments::<br><br> Url = str<br><br> def retry(url: Url, retry_count: int) -> None: ...<br><br>Note that we recommend capitalizing alias names, since they represent<br>user-defined types, which (like user-defined classes) are typically<br>spelled that way.<br><br>Type aliases may be as complex as type hints in annotations --<br>anything that is acceptable as a type hint is acceptable in a type<br>alias::<br><br> from typing import TypeVar, Iterable, Tuple<br><br> T = TypeVar('T', int, float, complex)<br> Vector = Iterable[Tuple[T, T]]<br><br> def inproduct(v: Vector) -> T:<br> return sum(x*y for x, y in v)<br><br>This is equivalent to::<br><br> from typing import TypeVar, Iterable, Tuple<br><br> T = TypeVar('T', int, float, complex)<br><br> def inproduct(v: Iterable[Tuple[T, T]]) -> T:<br> return sum(x*y for x, y in v)<br><br><br>Callable<br>--------<br><br>Frameworks expecting callback functions of specific signatures might be<br>type hinted using ``Callable[[Arg1Type, Arg2Type], ReturnType]``.<br>Examples::<br><br> from typing import Callable<br><br> def feeder(get_next_item: Callable[[], str]) -> None:<br> # Body<br><br> def async_query(on_success: Callable[[int], None],<br> on_error: Callable[[int, Exception], None]) -> None:<br> # Body<br><br>It is possible to declare the return type of a callable without<br>specifying the call signature by substituting a literal ellipsis<br>(three dots) for the list of arguments::<br><br> def partial(func: Callable[..., str], *args) -> Callable[..., str]:<br> # Body<br><br>Note that there are no square brackets around the ellipsis. The<br>arguments of the callback are completely unconstrained in this case<br>(and keyword arguments are acceptable).<br><br>Since using callbacks with keyword arguments is not perceived as a<br>common use case, there is currently no support for specifying keyword<br>arguments with ``Callable``. Similarly, there is no support for<br>specifying callback signatures with a variable number of argument of a<br>specific type.<br><br><br>Generics<br>--------<br><br>Since type information about objects kept in containers cannot be<br>statically inferred in a generic way, abstract base classes have been<br>extended to support subscription to denote expected types for container<br>elements. Example::<br><br> from typing import Mapping, Set<br><br> def notify_by_email(employees: Set[Employee], overrides: Mapping[str, str]) -> None: ...<br><br>Generics can be parametrized by using a new factory available in<br>``typing`` called ``TypeVar``. Example::<br><br> from typing import Sequence, TypeVar<br><br> T = TypeVar('T') # Declare type variable<br><br> def first(l: Sequence[T]) -> T: # Generic function<br> return l[0]<br><br>In this case the contract is that the returned value is consistent with<br>the elements held by the collection.<br><br>A ``TypeVar()`` expression must always directly be assigned to a<br>variable (it should not be used as part of a larger expression). The<br>argument to ``TypeVar()`` must be a string equal to the variable name<br>to which it is assigned. Type variables must not be redefined.<br><br>``TypeVar`` supports constraining parametric types to a fixed set of<br>possible types. For example, we can define a type variable that ranges<br>over just ``str`` and ``bytes``. By default, a type variable ranges<br>over all possible types. Example of constraining a type variable::<br><br> from typing import TypeVar<br><br> AnyStr = TypeVar('AnyStr', str, bytes)<br><br> def concat(x: AnyStr, y: AnyStr) -> AnyStr:<br> return x + y<br><br>The function ``concat`` can be called with either two ``str`` arguments<br>or two ``bytes`` arguments, but not with a mix of ``str`` and ``bytes``<br>arguments.<br><br>There should be at least two constraints, if any; specifying a single<br>constraint is disallowed.<br><br>Subtypes of types constrained by a type variable should be treated<br>as their respective explicitly listed base types in the context of the<br>type variable. Consider this example::<br><br> class MyStr(str): ...<br><br> x = concat(MyStr('apple'), MyStr('pie'))<br><br>The call is valid but the type variable ``AnyStr`` will be set to<br>``str`` and not ``MyStr``. In effect, the inferred type of the return<br>value assigned to ``x`` will also be ``str``.<br><br>Additionally, ``Any`` is a valid value for every type variable.<br>Consider the following::<br><br> def count_truthy(elements: List[Any]) -> int:<br> return sum(1 for elem in elements if element)<br><br>This is equivalent to omitting the generic notation and just saying<br>``elements: List``.<br><br><br>User-defined generic types<br>--------------------------<br><br>You can include a ``Generic`` base class to define a user-defined class<br>as generic. Example::<br><br> from typing import TypeVar, Generic<br><br> T = TypeVar('T')<br><br> class LoggedVar(Generic[T]):<br> def __init__(self, value: T, name: str, logger: Logger) -> None:<br> <a href="http://self.name">self.name</a> = name<br> self.logger = logger<br> self.value = value<br><br> def set(self, new: T) -> None:<br> self.log('Set ' + repr(self.value))<br> self.value = new<br><br> def get(self) -> T:<br> self.log('Get ' + repr(self.value))<br> return self.value<br><br> def log(self, message: str) -> None:<br> <a href="http://self.logger.info">self.logger.info</a>('{}: {}'.format(<a href="http://self.name">self.name</a> message))<br><br>``Generic[T]`` as a base class defines that the class ``LoggedVar``<br>takes a single type parameter ``T``. This also makes ``T`` valid as<br>a type within the class body.<br><br>The ``Generic`` base class uses a metaclass that defines ``__getitem__``<br>so that ``LoggedVar[t]`` is valid as a type::<br><br> from typing import Iterable<br><br> def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:<br> for var in vars:<br> var.set(0)<br><br>A generic type can have any number of type variables, and type variables<br>may be constrained. This is valid::<br><br> from typing import TypeVar, Generic<br> ...<br><br> T = TypeVar('T')<br> S = TypeVar('S')<br><br> class Pair(Generic[T, S]):<br> ...<br><br>Each type variable argument to ``Generic`` must be distinct. This is<br>thus invalid::<br><br> from typing import TypeVar, Generic<br> ...<br><br> T = TypeVar('T')<br><br> class Pair(Generic[T, T]): # INVALID<br> ...<br><br>You can use multiple inheritance with ``Generic``::<br><br> from typing import TypeVar, Generic, Sized<br><br> T = TypeVar('T')<br><br> class LinkedList(Sized, Generic[T]):<br> ...<br><br>Subclassing a generic class without specifying type parameters assumes<br>``Any`` for each position. In the following example, ``MyIterable``<br>is not generic but implicitly inherits from ``Iterable[Any]``:<br><br> from typing import Iterable<br><br> class MyIterable(Iterable): # Same as Iterable[Any]<br> ...<br><br>Generic metaclasses are not supported.<br><br><br>Instantiating generic classes and type erasure<br>----------------------------------------------<br><br>Generic types like ``List`` or ``Sequence`` cannot be instantiated.<br>However, user-defined classes derived from them can be instantiated.<br>Suppose we write a ``Node`` class inheriting from ``Generic[T]``::<br><br> from typing import TypeVar, Generic<br><br> T = TypeVar('T')<br><br> class Node(Generic[T]):<br> ...<br><br>Now there are two ways we can instantiate this class; the type<br>inferred by a type checker may be different depending on the form we<br>use. The first way is to give the value of the type parameter<br>explicitly -- this overrides whatever type inference the type<br>checker would otherwise perform:<br><br> x = Node[T]() # The type inferred for x is Node[T].<br><br> y = Node[int]() # The type inferred for y is Node[int].<br><br>If no explicit types are given, the type checker is given some<br>freedom. Consider this code:<br><br> x = Node()<br><br>The inferred type could be ``Node[Any]``, as there isn't enough<br>context to infer a more precise type. Alternatively, a type checker<br>may reject the line and require an explicit annotation, like this:<br><br> x = Node() # type: Node[int] # Inferred type is Node[int].<br><br>A type checker with more powerful type inference could look at how<br>``x`` is used elsewhere in the file and try to infer a more precise<br>type such as ``Node[int]`` even without an explicit type annotation.<br>However, it is probably impossible to make such type inference work<br>well in all cases, since Python programs can be very dynamic.<br><br>This PEP doesn't specify the details of how type inference should<br>work. We allow different tools to experiment with various approaches.<br>We may give more explicit rules in future revisions.<br><br>At runtime the type is not preserved, and the class of ``x`` is just<br>``Node`` in all cases. This behavior is called "type erasure"; it is<br>common practice in languages with generics (e.g. Java, TypeScript).<br><br><br>Arbitrary generic types as base classes<br>---------------------------------------<br><br>``Generic[T]`` is only valid as a base class -- it's not a proper type.<br>However, user-defined generic types such as ``LinkedList[T]`` from the<br>above example and built-in generic types and ABCs such as ``List[T]``<br>and ``Iterable[T]`` are valid both as types and as base classes. For<br>example, we can define a subclass of ``Dict`` that specializes type<br>arguments::<br><br> from typing import Dict, List, Optional<br><br> class Node:<br> ...<br><br> class SymbolTable(Dict[str, List[Node]]):<br> def push(self, name: str, node: Node) -> None:<br> self.setdefault(name, []).append(node)<br><br> def pop(self, name: str) -> Node:<br> return self[name].pop()<br><br> def lookup(self, name: str) -> Optional[Node]:<br> nodes = self.get(name)<br> if nodes:<br> return nodes[-1]<br> return None<br><br>``SymbolTable`` is a subclass of ``dict`` and a subtype of ``Dict[str,<br>List[Node]]``.<br><br>If a generic base class has a type variable as a type argument, this<br>makes the defined class generic. For example, we can define a generic<br>``LinkedList`` class that is iterable and a container::<br><br> from typing import TypeVar, Iterable, Container<br><br> T = TypeVar('T')<br><br> class LinkedList(Iterable[T], Container[T]):<br> ...<br><br>Now ``LinkedList[int]`` is a valid type. Note that we can use ``T``<br>multiple times in the base class list, as long as we don't use the<br>same type variable ``T`` multiple times within ``Generic[...]``.<br><br>Also consider the following example::<br><br> from typing import TypeVar, Mapping<br><br> T = TypeVar('T')<br><br> class MyDict(Mapping[str, T]):<br> ...<br><br>In this case MyDict has a single parameter, T.<br><br><br>Abstract generic types<br>----------------------<br><br>The metaclass used by ``Generic`` is a subclass of ``abc.ABCMeta``.<br>A generic class can be an ABC by including abstract methods<br>or properties, and generic classes can also have ABCs as base<br>classes without a metaclass conflict.<br><br><br>Type variables with an upper bound<br>----------------------------------<br><br>A type variable may specify an upper bound using ``bound=<type>``.<br>This means that an actual type substituted (explicitly or implictly)<br>for the type variable must be a subclass of the boundary type. A<br>common example is the definition of a Comparable type that works well<br>enough to catch the most common errors::<br><br> from typing import TypeVar<br><br> class Comparable(metaclass=ABCMeta):<br> @abstractmethod<br> def __lt__(self, other: Any) -> bool: ...<br> ... # __gt__ etc. as well<br><br> CT = TypeVar('CT', bound=Comparable)<br><br> def min(x: CT, y: CT) -> CT:<br> if x < y:<br> return x<br> else:<br> return y<br><br> min(1, 2) # ok, return type int<br> min('x', 'y') # ok, return type str<br><br>(Note that this is not ideal -- for example ``min('x', 1)`` is invalid<br>at runtime but a type checker would simply infer the return type<br>``Comparable``. Unfortunately, addressing this would require<br>introducing a much more powerful and also much more complicated<br>concept, F-bounded polymorphism. We may revisit this in the future.)<br><br>An upper bound cannot be combined with type constraints (as in used<br>``AnyStr``, see the example earlier); type constraints cause the<br>inferred type to be _exactly_ one of the constraint types, while an<br>upper bound just requires that the actual type is a subclass of the<br>boundary type.<br><br><br>Covariance and contravariance<br>-----------------------------<br><br>Consider a class ``Employee`` with a subclass ``Manager``. Now<br>suppose we have a function with an argument annotated with<br>``List[Employee]``. Should we be allowed to call this function with a<br>variable of type ``List[Manager]`` as its argument? Many people would<br>answer "yes, of course" without even considering the consequences.<br>But unless we know more about the function, a type checker should<br>reject such a call: the function might append an ``Employee`` instance<br>to the list, which would violate the variable's type in the caller.<br><br>It turns out such an argument acts _contravariantly_, whereas the<br>intuitive answer (which is correct in case the function doesn't mutate<br>its argument!) requires the argument to act _covariantly_. A longer<br>introduction to these concepts can be found on Wikipedia<br>[wiki-variance]_; here we just show how to control a type checker's<br>behavior.<br><br>By default type variables are considered _invariant_, which means that<br>arguments for arguments annotated with types like ``List[Employee]``<br>must exactly match the type annotation -- no subclasses or<br>superclasses of the type parameter (in this example ``Employee``) are<br>allowed.<br><br>To facilitate the declaration of container types where covariant type<br>checking is acceptable, a type variable can be declared using<br>``covariant=True``. For the (rare) case where contravariant behavior<br>is desirable, pass ``contravariant=True``. At most one of these may<br>be passed.<br><br>A typical example involves defining an immutable (or read-only)<br>container class::<br><br> from typing import TypeVar, Generic, Iterable, Iterator<br><br> T = TypeVar('T', covariant=True)<br><br> class ImmutableList(Generic[T]):<br> def __init__(self, items: Iterable[T]) -> None: ...<br> def __iter__(self) -> Iterator[T]: ...<br> ...<br><br> class Employee: ...<br><br> class Manager(Employee): ...<br><br> def dump_employees(emps: ImmutableList[Employee]) -> None:<br> for emp in emps:<br> ...<br><br> mgrs = ImmutableList([Manager()]) # type: ImmutableList[Manager]<br> dump_employees(mgrs) # OK<br><br>The read-only collection classes in ``typing`` are all defined using a<br>covariant type variable (e.g. ``Mapping`` and ``Sequence``). The<br>mutable collection classes (e.g. ``MutableMapping`` and<br>``MutableSequence``) are defined using regular invariant type<br>variables. The one example of a contravariant type variable is the<br>``Generator`` type, which is contravariant in the ``send()`` argument<br>type (see below).<br><br>Note: variance affects type parameters for generic types -- it does<br>not affect regular parameters. For example, the following example is<br>fine::<br><br> from typing import TypeVar<br><br> class Employee: ...<br><br> class Manager(Employee): ...<br><br> E = TypeVar('E', bound=Employee) # Invariant<br><br> def dump_employee(e: E) -> None: ...<br><br> dump_employee(Manager()) # OK<br><br><br>The numeric tower<br>-----------------<br><br>PEP 3141 defines Python's numeric tower, and the stdlib module<br>``numbers`` implements the corresponding ABCs (``Number``,<br>``Complex``, ``Real``, ``Rational`` and ``Integral``). There are some<br>issues with these ABCs, but the built-in concrete numeric classes<br>``complex``, ``float`` and ``int`` are ubiquitous (especially the<br>latter two :-).<br><br>Rather than requiring that users write ``import numbers`` and then use<br>``numbers.Float`` etc., this PEP proposes a straightforward shortcut<br>that is almost as effective: when an argument is annotated as having<br>type ``float``, an argument of type ``int`` is acceptable; similar,<br>for an argument annotated as having type ``complex``, arguments of<br>type ``float`` or ``int`` are acceptable. This does not handle<br>classes implementing the corresponding ABCs or the<br>``fractions.Fraction`` class, but we believe those use cases are<br>exceedingly rare.<br><br><br>The bytes types<br>---------------<br><br>There are three different builtin classes used for arrays of bytes<br>(not counting the classes available in the ``array`` module):<br>``bytes``, ``bytearray`` and ``memoryview``. Of these, ``bytes`` and<br>``bytearray`` have many behaviors in common (though not all --<br>``bytearray`` is mutable).<br><br>While there is an ABC ``ByteString`` defined in ``collections.abc``<br>and a corresponding type in ``typing``, functions accepting bytes (of<br>some form) are so common that it would be cumbersome to have to write<br>``typing.ByteString`` everywhere. So, as a shortcut similar to that<br>for the builtin numeric classes, when an argument is annotated as<br>having type ``bytes``, arguments of type ``bytearray`` or<br>``memoryview`` are acceptable. (Again, there are situations where<br>this isn't sound, but we believe those are exceedingly rare in<br>practice.)<br><br><br>Forward references<br>------------------<br><br>When a type hint contains names that have not been defined yet, that<br>definition may be expressed as a string literal, to be resolved later.<br><br>A situation where this occurs commonly is the definition of a<br>container class, where the class being defined occurs in the signature<br>of some of the methods. For example, the following code (the start of<br>a simple binary tree implementation) does not work::<br><br> class Tree:<br> def __init__(self, left: Tree, right: Tree):<br> self.left = left<br> self.right = right<br><br>To address this, we write::<br><br> class Tree:<br> def __init__(self, left: 'Tree', right: 'Tree'):<br> self.left = left<br> self.right = right<br><br>The string literal should contain a valid Python expression (i.e.,<br>``compile(lit, '', 'eval')`` should be a valid code object) and it<br>should evaluate without errors once the module has been fully loaded.<br>The local and global namespace in which it is evaluated should be the<br>same namespaces in which default arguments to the same function would<br>be evaluated.<br><br>Moreover, the expression should be parseable as a valid type hint, i.e.,<br>it is constrained by the rules from the section `Acceptable type hints`_<br>above.<br><br>It is allowable to use string literals as *part* of a type hint, for<br>example::<br><br> class Tree:<br> ...<br> def leaves(self) -> List['Tree']:<br> ...<br><br>A common use for forward references is when e.g. Django models are<br>needed in the signatures. Typically, each model is in a separate<br>file, and has methods that arguments whose type involves other models.<br>Because of the way circular imports work in Python, it is often not<br>possible to import all the needed models directly::<br><br> # File models/a.py<br> from models.b import B<br> class A(Model):<br> def foo(self, b: B): ...<br><br> # File models/b.py<br> from models.a import A<br> class B(Model):<br> def bar(self, a: A): ...<br><br> # File main.py<br> from models.a import A<br> from models.b import B<br><br>Assuming main is imported first, this will fail with an ImportError at<br>the line ``from models.a import A`` in models/b.py, which is being<br>imported from models/a.py before a has defined class A. The solution<br>is to switch to module-only imports and reference the models by their<br>_module_._class_ name::<br><br> # File models/a.py<br> from models import b<br> class A(Model):<br> def foo(self, b: 'b.B'): ...<br><br> # File models/b.py<br> from models import a<br> class B(Model):<br> def bar(self, a: 'a.A'): ...<br><br> # File main.py<br> from models.a import A<br> from models.b import B<br><br><br>Union types<br>-----------<br><br>Since accepting a small, limited set of expected types for a single<br>argument is common, there is a new special factory called ``Union``.<br>Example::<br><br> from typing import Union<br><br> def handle_employees(e: Union[Employee, Sequence[Employee]]) -> None:<br> if isinstance(e, Employee):<br> e = [e]<br> ...<br><br>A type factored by ``Union[T1, T2, ...]`` responds ``True`` to<br>``issubclass`` checks for ``T1`` and any of its subtypes, ``T2`` and<br>any of its subtypes, and so on.<br><br>One common case of union types are *optional* types. By default,<br>``None`` is an invalid value for any type, unless a default value of<br>``None`` has been provided in the function definition. Examples::<br><br> def handle_employee(e: Union[Employee, None]) -> None: ...<br><br>As a shorthand for ``Union[T1, None]`` you can write ``Optional[T1]``;<br>for example, the above is equivalent to::<br><br> from typing import Optional<br><br> def handle_employee(e: Optional[Employee]) -> None: ...<br><br>An optional type is also automatically assumed when the default value is<br>``None``, for example::<br><br> def handle_employee(e: Employee = None): ...<br><br>This is equivalent to::<br><br> def handle_employee(e: Optional[Employee] = None) -> None: ...<br><br>The ``Any`` type<br>----------------<br><br>A special kind of type is ``Any``. Every type is a subtype of<br>``Any``. This is also true for the builtin type ``object``.<br>However, to the static type checker these are completely different.<br><br>When the type of a value is ``object``, the type checker will reject<br>almost all operations on it, and assigning it to a variable (or using<br>it as a return value) of a more specialized type is a type error. On<br>the other hand, when a value has type ``Any``, the type checker will<br>allow all operations on it, and a value of type ``Any`` can be assigned<br>to a variable (or used as a return value) of a more constrained type.<br><br><br>Version and platform checking<br>-----------------------------<br><br>Type checkers are expected to understand simple version and platform<br>checks, e.g.::<br><br> import sys<br><br> if sys.version_info[0] >= 3:<br> # Python 3 specific definitions<br> else:<br> # Python 2 specific definitions<br><br> if sys.platform == 'win32':<br> # Windows specific definitions<br> else:<br> # Posix specific definitions<br><br>Don't expect a checker to understand obfuscations like<br>``"".join(reversed(sys.platform)) == "xunil"``.<br><br><br>Default argument values<br>-----------------------<br><br>In stubs it may be useful to declare an argument as having a default<br>without specifying the actual default value. For example::<br><br> def foo(x: AnyStr, y: AnyStr = ...) -> AnyStr: ...<br><br>What should the default value look like? Any of the options ``""``,<br>``b""`` or ``None`` fails to satisfy the type constraint (actually,<br>``None`` will *modify* the type to become ``Optional[AnyStr]``).<br><br>In such cases the default value may be specified as a literal<br>ellipsis, i.e. the above example is literally what you would write.<br><br><br>Compatibility with other uses of function annotations<br>=====================================================<br><br>A number of existing or potential use cases for function annotations<br>exist, which are incompatible with type hinting. These may confuse<br>a static type checker. However, since type hinting annotations have no<br>runtime behavior (other than evaluation of the annotation expression and<br>storing annotations in the ``__annotations__`` attribute of the function<br>object), this does not make the program incorrect -- it just may cause<br>a type checker to emit spurious warnings or errors.<br><br>To mark portions of the program that should not be covered by type<br>hinting, you can use one or more of the following:<br><br>* a ``# type: ignore`` comment;<br><br>* a ``@no_type_check`` decorator on a class or function;<br><br>* a custom class or function decorator marked with<br> ``@no_type_check_decorator``.<br><br>For more details see later sections.<br><br>In order for maximal compatibility with offline type checking it may<br>eventually be a good idea to change interfaces that rely on annotations<br>to switch to a different mechanism, for example a decorator. In Python<br>3.5 there is no pressure to do this, however. See also the longer<br>discussion under `Rejected alternatives`_ below.<br><br><br>Type comments<br>=============<br><br>No first-class syntax support for explicitly marking variables as being<br>of a specific type is added by this PEP. To help with type inference in<br>complex cases, a comment of the following format may be used::<br><br> x = [] # type: List[Employee]<br> x, y, z = [], [], [] # type: List[int], List[int], List[str]<br> x, y, z = [], [], [] # type: (List[int], List[int], List[str])<br> x = [<br> 1,<br> 2,<br> ] # type: List[int]<br><br>Type comments should be put on the last line of the statement that<br>contains the variable definition. They can also be placed on<br>``with`` statements and ``for`` statements, right after the colon.<br><br>Examples of type comments on ``with`` and ``for`` statements::<br><br> with frobnicate() as foo: # type: int<br> # Here foo is an int<br> ...<br><br> for x, y in points: # type: float, float<br> # Here x and y are floats<br> ...<br><br>In stubs it may be useful to declare the existence of a variable<br>without giving it an initial value. This can be done using a literal<br>ellipsis::<br><br> from typing import IO<br><br> stream = ... # type: IO[str]<br><br>In non-stub code, there is a similar special case:<br><br> from typing import IO<br><br> stream = None # type: IO[str]<br><br>Type checkers should not complain about this (despite the value<br>``None`` not matching the given type), nor should they change the<br>inferred type to ``Optional[...]`` (despite the rule that does this<br>for annotated arguments with a default value of ``None``). The<br>assumption here is that other code will ensure that the variable is<br>given a value of the proper type, and all uses can assume that the<br>variable has the given type.<br><br>The ``# type: ignore`` comment should be put on the line that the<br>error refers to::<br><br> import http.client<br> errors = {<br> 'not_found': http.client.NOT_FOUND # type: ignore<br> }<br><br>A ``# type: ignore`` comment on a line by itself disables all type<br>checking for the rest of the file.<br><br>If type hinting proves useful in general, a syntax for typing variables<br>may be provided in a future Python version.<br><br>Casts<br>=====<br><br>Occasionally the type checker may need a different kind of hint: the<br>programmer may know that an expression is of a more constrained type<br>than a type checker may be able to infer. For example::<br><br> from typing import List, cast<br><br> def find_first_str(a: List[object]) -> str:<br> index = next(i for i, x in enumerate(a) if isinstance(x, str))<br> # We only get here if there's at least one string in a<br> return cast(str, a[index])<br><br>Some type checkers may not be able to infer that the type of<br>``a[index]`` is ``str`` and only infer ``object`` or ``Any``", but we<br>know that (if the code gets to that point) it must be a string. The<br>``cast(t, x)`` call tells the type checker that we are confident that<br>the type of ``x`` is ``t``. At runtime a cast always returns the<br>expression unchanged -- it does not check the type, and it does not<br>convert or coerce the value.<br><br>Casts differ from type comments (see the previous section). When using<br>a type comment, the type checker should still verify that the inferred<br>type is consistent with the stated type. When using a cast, the type<br>checker should blindly believe the programmer. Also, casts can be used<br>in expressions, while type comments only apply to assignments.<br><br><br>Stub Files<br>==========<br><br>Stub files are files containing type hints that are only for use by<br>the type checker, not at runtime. There are several use cases for<br>stub files:<br><br>* Extension modules<br><br>* Third-party modules whose authors have not yet added type hints<br><br>* Standard library modules for which type hints have not yet been<br> written<br><br>* Modules that must be compatible with Python 2 and 3<br><br>* Modules that use annotations for other purposes<br><br>Stub files have the same syntax as regular Python modules. There is one<br>feature of the ``typing`` module that may only be used in stub files:<br>the ``@overload`` decorator described below.<br><br>The type checker should only check function signatures in stub files;<br>It is recommended that function bodies in stub files just be a single<br>ellipsis (``...``).<br><br>The type checker should have a configurable search path for stub files.<br>If a stub file is found the type checker should not read the<br>corresponding "real" module.<br><br>While stub files are syntactically valid Python modules, they use the<br>``.pyi`` extension to make it possible to maintain stub files in the<br>same directory as the corresponding real module. This also reinforces<br>the notion that no runtime behavior should be expected of stub files.<br><br>Additional notes on stub files:<br><br>* Modules and variables imported into the stub are not considered<br> exported from the stub unless the import uses the ``import ... as<br> ...`` form.<br><br>Function overloading<br>--------------------<br><br>The ``@overload`` decorator allows describing functions that support<br>multiple different combinations of argument types. This pattern is<br>used frequently in builtin modules and types. For example, the<br>``__getitem__()`` method of the ``bytes`` type can be described as<br>follows::<br><br> from typing import overload<br><br> class bytes:<br> ...<br> @overload<br> def __getitem__(self, i: int) -> int: ...<br> @overload<br> def __getitem__(self, s: slice) -> bytes: ...<br><br>This description is more precise than would be possible using unions<br>(which cannot express the relationship between the argument and return<br>types)::<br><br> from typing import Union<br><br> class bytes:<br> ...<br> def __getitem__(self, a: Union[int, slice]) -> Union[int, bytes]: ...<br><br>Another example where ``@overload`` comes in handy is the type of the<br>builtin ``map()`` function, which takes a different number of<br>arguments depending on the type of the callable::<br><br> from typing import Callable, Iterable, Iterator, Tuple, TypeVar, overload<br><br> T1 = TypeVar('T1')<br> T2 = TypeVar('T2)<br> S = TypeVar('S')<br><br> @overload<br> def map(func: Callable[[T1], S], iter1: Iterable[T1]) -> Iterator[S]: ...<br> @overload<br> def map(func: Callable[[T1, T2], S],<br> iter1: Iterable[T1], iter2: Iterable[T2]) -> Iterator[S]: ...<br> # ... and we could add more items to support more than two iterables<br><br>Note that we could also easily add items to support ``map(None, ...)``::<br><br> @overload<br> def map(func: None, iter1: Iterable[T1]) -> Iterable[T1]: ...<br> @overload<br> def map(func: None,<br> iter1: Iterable[T1],<br> iter2: Iterable[T2]) -> Iterable[Tuple[T1, T2]]: ...<br><br>The ``@overload`` decorator may only be used in stub files. While it<br>would be possible to provide a multiple dispatch implementation using<br>this syntax, its implementation would require using<br>``sys._getframe()``, which is frowned upon. Also, designing and<br>implementing an efficient multiple dispatch mechanism is hard, which<br>is why previous attempts were abandoned in favor of<br>``functools.singledispatch()``. (See PEP 443, especially its section<br>"Alternative approaches".) In the future we may come up with a<br>satisfactory multiple dispatch design, but we don't want such a design<br>to be constrained by the overloading syntax defined for type hints in<br>stub files. In the meantime, using the ``@overload`` decorator or<br>calling ``overload()`` directly raises ``RuntimeError``.<br><br>A constrained ``TypeVar`` type can often be used instead of using the<br>``@overload`` decorator. For example, the definitions of ``concat1``<br>and ``concat2`` in this stub file are equivalent:<br><br> from typing import TypeVar<br><br> AnyStr = TypeVar('AnyStr', str, bytes)<br><br> def concat1(x: AnyStr, y: AnyStr) -> AnyStr: ...<br><br> @overload<br> def concat2(x: str, y: str) -> str: ...<br> @overload<br> def concat2(x: bytes, y: bytes) -> bytes: ...<br><br>Some functions, such as ``map`` or ``bytes.__getitem__`` above, can't<br>be represented precisely using type variables. However, unlike<br>``@overload``, type variables can also be used outside stub files. We<br>recommend that ``@overload`` is only used in cases where a type<br>variable is not sufficient, due to its special stub-only status.<br><br>Another important difference between type variables such as ``AnyStr``<br>and using ``@overload`` is that the prior can also be used to define<br>constraints for generic class type parameters. For example, the type<br>parameter of the generic class ``typing.IO`` is constrained (only<br>``IO[str]``, ``IO[bytes]`` and ``IO[Any]`` are valid):<br><br> class IO(Generic[AnyStr]): ...<br><br>Storing and distributing stub files<br>-----------------------------------<br><br>The easiest form of stub file storage and distribution is to put them<br>alongside Python modules in the same directory. This makes them easy to<br>find by both programmers and the tools. However, since package<br>maintainers are free not to add type hinting to their packages,<br>third-party stubs installable by ``pip`` from PyPI are also supported.<br>In this case we have to consider three issues: naming, versioning,<br>installation path.<br><br>This PEP does not provide a recommendation on a naming scheme that<br>should be used for third-party stub file packages. Discoverability will<br>hopefully be based on package popularity, like with Django packages for<br>example.<br><br>Third-party stubs have to be versioned using the lowest version of the<br>source package that is compatible. Example: FooPackage has versions<br>1.0, 1.1, 1.2, 1.3, 2.0, 2.1, 2.2. There are API changes in versions<br>1.1, 2.0 and 2.2. The stub file package maintainer is free to release<br>stubs for all versions but at least 1.0, 1.1, 2.0 and 2.2 are needed<br>to enable the end user type check all versions. This is because the<br>user knows that the closest *lower or equal* version of stubs is<br>compatible. In the provided example, for FooPackage 1.3 the user would<br>choose stubs version 1.1.<br><br>Note that if the user decides to use the "latest" available source<br>package, using the "latest" stub files should generally also work if<br>they're updated often.<br><br>Third-party stub packages can use any location for stub storage. Type<br>checkers should search for them using PYTHONPATH. A default fallback<br>directory that is always checked is ``shared/typehints/python3.5/`` (or<br>3.6, etc.). Since there can only be one package installed for a given<br>Python version per environment, no additional versioning is performed<br>under that directory (just like bare directory installs by ``pip`` in<br>site-packages). Stub file package authors might use the following<br>snippet in ``setup.py``::<br><br> ...<br> data_files=[<br> (<br> 'shared/typehints/python{}.{}'.format(*sys.version_info[:2]),<br> pathlib.Path(SRC_PATH).glob('**/*.pyi'),<br> ),<br> ],<br> ...<br><br>The Typeshed Repo<br>-----------------<br><br>There is a shared repository where useful stubs are being collected<br>[typeshed]_. Note that stubs for a given package will not be included<br>here without the explicit consent of the package owner. Further<br>policies regarding the stubs collected here will be decided at a later<br>time, after discussion on python-dev, and reported in the typeshed<br>repo's README.<br><br><br>Exceptions<br>==========<br><br>No syntax for listing explicitly raised exceptions is proposed.<br>Currently the only known use case for this feature is documentational,<br>in which case the recommendation is to put this information in a<br>docstring.<br><br><br>The ``typing`` Module<br>=====================<br><br>To open the usage of static type checking to Python 3.5 as well as older<br>versions, a uniform namespace is required. For this purpose, a new<br>module in the standard library is introduced called ``typing``.<br><br>It defines the fundamental building blocks for constructing types<br>(e.g. ``Any``), types representing generic variants of builtin<br>collections (e.g. ``List``), types representing generic<br>collection ABCs (e.g. ``Sequence``), and a small collection of<br>convenience definitions.<br><br>Fundamental building blocks:<br><br>* Any, used as ``def get(key: str) -> Any: ...``<br><br>* Union, used as ``Union[Type1, Type2, Type3]``<br><br>* Callable, used as ``Callable[[Arg1Type, Arg2Type], ReturnType]``<br><br>* Tuple, used by listing the element types, for example<br> ``Tuple[int, int, str]``.<br> Arbitrary-length homogeneous tuples can be expressed<br> using one type and ellipsis, for example ``Tuple[int, ...]``.<br> (The ``...`` here are part of the syntax, a literal ellipsis.)<br><br>* TypeVar, used as ``X = TypeVar('X', Type1, Type2, Type3)`` or simply<br> ``Y = TypeVar('Y')`` (see above for more details)<br><br>* Generic, used to create user-defined generic classes<br><br>Generic variants of builtin collections:<br><br>* Dict, used as ``Dict[key_type, value_type]``<br><br>* List, used as ``List[element_type]``<br><br>* Set, used as ``Set[element_type]``. See remark for ``AbstractSet``<br> below.<br><br>* FrozenSet, used as ``FrozenSet[element_type]``<br><br>Note: ``Dict``, ``List``, ``Set`` and ``FrozenSet`` are mainly useful<br>for annotating return values. For arguments, prefer the abstract<br>collection types defined below, e.g. ``Mapping``, ``Sequence`` or<br>``AbstractSet``.<br><br>Generic variants of container ABCs (and a few non-containers):<br><br>* ByteString<br><br>* Callable (see above, listed here for completeness)<br><br>* Container<br><br>* Generator, used as ``Generator[yield_type, send_type,<br> return_type]``. This represents the return value of generator<br> functions. It is a subtype of ``Iterable`` and it has additional<br> type variables for the type accepted by the ``send()`` method (which<br> is contravariant -- a generator that accepts sending it ``Employee``<br> instance is valid in a context where a generator is required that<br> accepts sending it ``Manager`` instances) and the return type of the<br> generator.<br><br>* Hashable (not generic, but present for completeness)<br><br>* ItemsView<br><br>* Iterable<br><br>* Iterator<br><br>* KeysView<br><br>* Mapping<br><br>* MappingView<br><br>* MutableMapping<br><br>* MutableSequence<br><br>* MutableSet<br><br>* Sequence<br><br>* Set, renamed to ``AbstractSet``. This name change was required<br> because ``Set`` in the ``typing`` module means ``set()`` with<br> generics.<br><br>* Sized (not generic, but present for completeness)<br><br>* ValuesView<br><br>A few one-off types are defined that test for single special methods<br>(similar to ``Hashable`` or ``Sized``):<br><br>* Reversible, to test for ``__reversed__``<br><br>* SupportsAbs, to test for ``__abs__``<br><br>* SupportsComplex, to test for ``__complex__``<br><br>* SupportsFloat, to test for ``__float__``<br><br>* SupportsInt, to test for ``__int__``<br><br>* SupportsRound, to test for ``__round__``<br><br>* SupportsBytes, to test for ``__bytes__``<br><br>Convenience definitions:<br><br>* Optional, defined by ``Optional[t] == Union[t, type(None)]``<br><br>* AnyStr, defined as ``TypeVar('AnyStr', str, bytes)``<br><br>* NamedTuple, used as<br> ``NamedTuple(type_name, [(field_name, field_type), ...])``<br> and equivalent to<br> ``collections.namedtuple(type_name, [field_name, ...])``.<br> This is useful to declare the types of the fields of a a named tuple<br> type.<br><br>* cast(), described earlier<br><br>* @no_type_check, a decorator to disable type checking per class or<br> function (see below)<br><br>* @no_type_check_decorator, a decorator to create your own decorators<br> with the same meaning as ``@no_type_check`` (see below)<br><br>* @overload, described earlier<br><br>* get_type_hints(), a utility function to retrieve the type hints from a<br> function or method. Given a function or method object, it returns<br> a dict with the same format as ``__annotations__``, but evaluating<br> forward references (which are given as string literals) as expressions<br> in the context of the original function or method definition.<br><br>Types available in the ``<a href="http://typing.io">typing.io</a>`` submodule:<br><br>* IO (generic over ``AnyStr``)<br><br>* BinaryIO (a simple subtype of ``IO[bytes]``)<br><br>* TextIO (a simple subtype of ``IO[str]``)<br><br>Types available in the ``<a href="http://typing.re">typing.re</a>`` submodule:<br><br>* Match and Pattern, types of ``re.match()`` and ``re.compile()``<br> results (generic over ``AnyStr``)<br><br><br>Rejected Alternatives<br>=====================<br><br>During discussion of earlier drafts of this PEP, various objections<br>were raised and alternatives were proposed. We discuss some of these<br>here and explain why we reject them.<br><br>Several main objections were raised.<br><br>Which brackets for generic type parameters?<br>-------------------------------------------<br><br>Most people are familiar with the use of angular brackets<br>(e.g. ``List<int>``) in languages like C++, Java, C# and Swift to<br>express the parametrization of generic types. The problem with these<br>is that they are really hard to parse, especially for a simple-minded<br>parser like Python. In most languages the ambiguities are usually<br>dealt with by only allowing angular brackets in specific syntactic<br>positions, where general expressions aren't allowed. (And also by<br>using very powerful parsing techniques that can backtrack over an<br>arbitrary section of code.)<br><br>But in Python, we'd like type expressions to be (syntactically) the<br>same as other expressions, so that we can use e.g. variable assignment<br>to create type aliases. Consider this simple type expression::<br><br> List<int><br><br>From the Python parser's perspective, the expression begins with the<br>same four tokens (NAME, LESS, NAME, GREATER) as a chained comparison::<br><br> a < b > c # I.e., (a < b) and (b > c)<br><br>We can even make up an example that could be parsed both ways::<br><br> a < b > [ c ]<br><br>Assuming we had angular brackets in the language, this could be<br>interpreted as either of the following two::<br><br> (a<b>)[c] # I.e., (a<b>).__getitem__(c)<br> a < b > ([c]) # I.e., (a < b) and (b > [c])<br><br>It would surely be possible to come up with a rule to disambiguate<br>such cases, but to most users the rules would feel arbitrary and<br>complex. It would also require us to dramatically change the CPython<br>parser (and every other parser for Python). It should be noted that<br>Python's current parser is intentionally "dumb" -- a simple grammar is<br>easier for users to reason about.<br><br>For all these reasons, square brackets (e.g. ``List[int]``) are (and<br>have long been) the preferred syntax for generic type parameters.<br>They can be implemented by defining the ``__getitem__()`` method on<br>the metaclass, and no new syntax is required at all. This option<br>works in all recent versions of Python (starting with Python 2.2).<br>Python is not alone in this syntactic choice -- generic classes in<br>Scala also use square brackets.<br><br>What about existing uses of annotations?<br>----------------------------------------<br><br>One line of argument points out that PEP 3107 explicitly supports<br>the use of arbitrary expressions in function annotations. The new<br>proposal is then considered incompatible with the specification of PEP<br>3107.<br><br>Our response to this is that, first of all, the current proposal does<br>not introduce any direct incompatibilities, so programs using<br>annotations in Python 3.4 will still work correctly and without<br>prejudice in Python 3.5.<br><br>We do hope that type hints will eventually become the sole use for<br>annotations, but this will require additional discussion and a<br>deprecation period after the initial roll-out of the typing module<br>with Python 3.5. The current PEP will have provisional status (see<br>PEP 411) until Python 3.6 is released. The fastest conceivable scheme<br>would introduce silent deprecation of non-type-hint annotations in<br>3.6, full deprecation in 3.7, and declare type hints as the only<br>allowed use of annotations in Python 3.8. This should give authors of<br>packages that use annotations plenty of time to devise another<br>approach, even if type hints become an overnight success.<br><br>Another possible outcome would be that type hints will eventually<br>become the default meaning for annotations, but that there will always<br>remain an option to disable them. For this purpose the current<br>proposal defines a decorator ``@no_type_check`` which disables the<br>default interpretation of annotations as type hints in a given class<br>or function. It also defines a meta-decorator<br>``@no_type_check_decorator`` which can be used to decorate a decorator<br>(!), causing annotations in any function or class decorated with the<br>latter to be ignored by the type checker.<br><br>There are also ``# type: ignore`` comments, and static checkers should<br>support configuration options to disable type checking in selected<br>packages.<br><br>Despite all these options, proposals have been circulated to allow<br>type hints and other forms of annotations to coexist for individual<br>arguments. One proposal suggests that if an annotation for a given<br>argument is a dictionary literal, each key represents a different form<br>of annotation, and the key ``'type'`` would be use for type hints.<br>The problem with this idea and its variants is that the notation<br>becomes very "noisy" and hard to read. Also, in most cases where<br>existing libraries use annotations, there would be little need to<br>combine them with type hints. So the simpler approach of selectively<br>disabling type hints appears sufficient.<br><br>The problem of forward declarations<br>-----------------------------------<br><br>The current proposal is admittedly sub-optimal when type hints must<br>contain forward references. Python requires all names to be defined<br>by the time they are used. Apart from circular imports this is rarely<br>a problem: "use" here means "look up at runtime", and with most<br>"forward" references there is no problem in ensuring that a name is<br>defined before the function using it is called.<br><br>The problem with type hints is that annotations (per PEP 3107, and<br>similar to default values) are evaluated at the time a function is<br>defined, and thus any names used in an annotation must be already<br>defined when the function is being defined. A common scenario is a<br>class definition whose methods need to reference the class itself in<br>their annotations. (More general, it can also occur with mutually<br>recursive classes.) This is natural for container types, for<br>example::<br><br> class Node:<br> """Binary tree node."""<br><br> def __init__(self, left: Node, right: None):<br> self.left = left<br> self.right = right<br><br>As written this will not work, because of the peculiarity in Python<br>that class names become defined once the entire body of the class has<br>been executed. Our solution, which isn't particularly elegant, but<br>gets the job done, is to allow using string literals in annotations.<br>Most of the time you won't have to use this though -- most *uses* of<br>type hints are expected to reference builtin types or types defined in<br>other modules.<br><br>A counterproposal would change the semantics of type hints so they<br>aren't evaluated at runtime at all (after all, type checking happens<br>off-line, so why would type hints need to be evaluated at runtime at<br>all). This of course would run afoul of backwards compatibility,<br>since the Python interpreter doesn't actually know whether a<br>particular annotation is meant to be a type hint or something else.<br><br>A compromise is possible where a ``__future__`` import could enable<br>turning *all* annotations in a given module into string literals, as<br>follows::<br><br> from __future__ import annotations<br><br> class ImSet:<br> def add(self, a: ImSet) -> List[ImSet]: ...<br><br> assert ImSet.add.__annotations__ == {'a': 'ImSet', 'return': 'List[ImSet]'}<br><br>Such a ``__future__`` import statement may be proposed in a separate<br>PEP.<br><br><br>The double colon<br>----------------<br><br>A few creative souls have tried to invent solutions for this problem.<br>For example, it was proposed to use a double colon (``::``) for type<br>hints, solving two problems at once: disambiguating between type hints<br>and other annotations, and changing the semantics to preclude runtime<br>evaluation. There are several things wrong with this idea, however.<br><br>* It's ugly. The single colon in Python has many uses, and all of<br> them look familiar because they resemble the use of the colon in<br> English text. This is a general rule of thumb by which Python<br> abides for most forms of punctuation; the exceptions are typically<br> well known from other programming languages. But this use of ``::``<br> is unheard of in English, and in other languages (e.g. C++) it is<br> used as a scoping operator, which is a very different beast. In<br> contrast, the single colon for type hints reads naturally -- and no<br> wonder, since it was carefully designed for this purpose (the idea<br> long predates PEP 3107 [gvr-artima]_). It is also used in the same<br> fashion in other languages from Pascal to Swift.<br><br>* What would you do for return type annotations?<br><br>* It's actually a feature that type hints are evaluated at runtime.<br><br> * Making type hints available at runtime allows runtime type<br> checkers to be built on top of type hints.<br><br> * It catches mistakes even when the type checker is not run. Since<br> it is a separate program, users may choose not to run it (or even<br> install it), but might still want to use type hints as a concise<br> form of documentation. Broken type hints are no use even for<br> documentation.<br><br>* Because it's new syntax, using the double colon for type hints would<br> limit them to code that works with Python 3.5 only. By using<br> existing syntax, the current proposal can easily work for older<br> versions of Python 3. (And in fact mypy supports Python 3.2 and<br> newer.)<br><br>* If type hints become successful we may well decide to add new syntax<br> in the future to declare the type for variables, for example<br> ``var age: int = 42``. If we were to use a double colon for<br> argument type hints, for consistency we'd have to use the same<br> convention for future syntax, perpetuating the ugliness.<br><br>Other forms of new syntax<br>-------------------------<br><br>A few other forms of alternative syntax have been proposed, e.g. the<br>introduction of a ``where`` keyword [roberge]_, and Cobra-inspired<br>``requires`` clauses. But these all share a problem with the double<br>colon: they won't work for earlier versions of Python 3. The same<br>would apply to a new ``__future__`` import.<br><br>Other backwards compatible conventions<br>--------------------------------------<br><br>The ideas put forward include:<br><br>* A decorator, e.g. ``@typehints(name=str, returns=str)``. This could<br> work, but it's pretty verbose (an extra line, and the argument names<br> must be repeated), and a far cry in elegance from the PEP 3107<br> notation.<br><br>* Stub files. We do want stub files, but they are primarily useful<br> for adding type hints to existing code that doesn't lend itself to<br> adding type hints, e.g. 3rd party packages, code that needs to<br> support both Python 2 and Python 3, and especially extension<br> modules. For most situations, having the annotations in line with<br> the function definitions makes them much more useful.<br><br>* Docstrings. There is an existing convention for docstrings, based<br> on the Sphinx notation (``:type arg1: description``). This is<br> pretty verbose (an extra line per parameter), and not very elegant.<br> We could also make up something new, but the annotation syntax is<br> hard to beat (because it was designed for this very purpose).<br><br>It's also been proposed to simply wait another release. But what<br>problem would that solve? It would just be procrastination.<br><br><br>PEP Development Process<br>=======================<br><br>A live draft for this PEP lives on GitHub [github]_. There is also an<br>issue tracker [issues]_, where much of the technical discussion takes<br>place.<br><br>The draft on GitHub is updated regularly in small increments. The<br>official PEPS repo [peps_] is (usually) only updated when a new draft<br>is posted to python-dev.<br><br><br>Acknowledgements<br>================<br><br>This document could not be completed without valuable input,<br>encouragement and advice from Jim Baker, Jeremy Siek, Michael Matson<br>Vitousek, Andrey Vlasovskikh, Radomir Dopieralski, Peter Ludemann,<br>and the BDFL-Delegate, Mark Shannon.<br><br>Influences include existing languages, libraries and frameworks<br>mentioned in PEP 482. Many thanks to their creators, in alphabetical<br>order: Stefan Behnel, William Edwards, Greg Ewing, Larry Hastings,<br>Anders Hejlsberg, Alok Menghrajani, Travis E. Oliphant, Joe Pamer,<br>Raoul-Gabriel Urma, and Julien Verlaguet.<br><br><br>References<br>==========<br><br>.. [mypy]<br> <a href="http://mypy-lang.org">http://mypy-lang.org</a><br><br>.. [gvr-artima]<br> <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=85551">http://www.artima.com/weblogs/viewpost.jsp?thread=85551</a><br><br>.. [wiki-variance]<br> <a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29">http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29</a><br><br>.. [typeshed]<br> <a href="https://github.com/JukkaL/typeshed/">https://github.com/JukkaL/typeshed/</a><br><br>.. [pyflakes]<br> <a href="https://github.com/pyflakes/pyflakes/">https://github.com/pyflakes/pyflakes/</a><br><br>.. [pylint]<br> <a href="http://www.pylint.org">http://www.pylint.org</a><br><br>.. [roberge]<br> <a href="http://aroberge.blogspot.com/2015/01/type-hinting-in-python-focus-on.html">http://aroberge.blogspot.com/2015/01/type-hinting-in-python-focus-on.html</a><br><br>.. [github]<br> <a href="https://github.com/ambv/typehinting">https://github.com/ambv/typehinting</a><br><br>.. [issues]<br> <a href="https://github.com/ambv/typehinting/issues">https://github.com/ambv/typehinting/issues</a><br><br>.. [peps]<br> <a href="https://hg.python.org/peps/file/tip/pep-0484.txt">https://hg.python.org/peps/file/tip/pep-0484.txt</a><br><br><br>Copyright<br>=========<br><br>This document has been placed in the public domain.<br><br><br><br>..<br> Local Variables:<br> mode: indented-text<br> indent-tabs-mode: nil<br> sentence-end-double-space: t<br> fill-column: 70<br> coding: utf-8<br> End:<br><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div></div></div></div></div>