<div dir="ltr">After a long editing process we've got <a href="https://www.python.org/dev/peps/pep-0484/" target="_blank">PEP 484</a> (Type Hints) ready for your review. This is by no means final, and several areas are either open (to be resolved in a later draft) or postponed (to a different PEP altogether). But there's enough meat that I think we can start having the discussion. Please also see <a href="https://www.python.org/dev/peps/pep-0483/">PEP 483</a> (The Theory of Type Hint; copied and reformatted from the original Quip document that I posted just before last Christmas) and <a href="https://www.python.org/dev/peps/pep-0482/">PEP 482</a> (Literature Overview for Type Hints, by Łukasz). Those are informational PEPs though; the actual spec is focused in PEP 484 (the only one on the Standards Track).<br><br>As I said earlier, I hope to have a rough consensus before <a href="https://us.pycon.org/2015/" target="_blank">PyCon</a> and working code (just the <a href="https://github.com/ambv/typehinting/tree/master/prototyping" target="_blank">typing.py module</a>, really) committed to CPython before <a href="https://www.python.org/dev/peps/pep-0478/" target="_blank">the last 3.5 alpha</a>.<br><br>Here is the raw text of PEP 484. Fire away!!<br><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>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<br>Resolution:<br><br><br>Abstract<br>========<br><br>This PEP introduces a standard syntax for type hints using annotations<br>on function definitions.<br><br>The proposal is strongly inspired by mypy [mypy]_.<br><br>The theory behind type hints and gradual typing is explained in PEP 483.<br><br><br>Rationale and Goals<br>===================<br><br>PEP 3107 added support for arbitrary annotations on parts of a function<br>definition.  Although no meaning was assigned to annotations then, there<br>has always been an implicit goal to use them for type hinting, which is<br>listed as the first possible use case in said PEP.<br><br>This PEP aims to provide a standard syntax for type annotations, opening<br>up Python code to easier static analysis and refactoring, potential<br>runtime type checking, and performance optimizations utilizing type<br>information.<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 hinting<br>is used by filling function annotations with classes::<br><br>  def greeting(name: str) -> str:<br>      return 'Hello ' + name<br><br>This denotes that the expected type of the ``name`` argument is ``str``.<br>Analogically, the expected return type is ``str``.  Subclasses of<br>a specified argument type are also accepted as valid types for that<br>argument.<br><br>Abstract base classes, types available in the ``types`` module, and<br>user-defined classes may be used as type hints as well.  Annotations<br>must be valid expressions that evaluate without raising exceptions at<br>the time the function is defined.  In addition, the needs of static<br>analysis require that annotations must be simple enough to be<br>interpreted by static analysis tools.  (This is an intentionally<br>somewhat vague requirement.)<br><br>.. FIXME: Define rigorously what is/isn't supported.<br><br>When used as an annotation, the expression ``None`` is considered<br>equivalent to ``NoneType`` (i.e., ``type(None)`` for type hinting<br>purposes.<br><br>Type aliases are also valid type hints::<br><br>  integer = int<br><br>  def retry(url: str, retry_count: integer): ...<br><br>New names that are added to support features described in following<br>sections are available in the ``typing`` package.<br><br><br>Callbacks<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 Any, AnyArgs, Callable<br><br>  def feeder(get_next_item: Callable[[], Item]): ...<br><br>  def async_query(on_success: Callable[[int], None], on_error: Callable[[int, Exception], None]): ...<br><br>  def partial(func: Callable[AnyArgs, Any], *args): ...<br><br>Since using callbacks with keyword arguments is not perceived as<br>a common use case, there is currently no support for specifying keyword<br>arguments with ``Callable``.<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]): ...<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 returning value is consistent with<br>the elements held by the collection.<br><br>``TypeVar`` supports constraining parametric types to classes with any of<br>the specified bases.  Example::<br><br>  from typing import Iterable<br><br>  X = TypeVar('X')<br>  Y = TypeVar('Y', Iterable[X])<br><br>  def filter(rule: Callable[[X], bool], input: Y) -> Y:<br>      ...<br><br>.. FIXME: Add an example with multiple bases defined.<br><br>In the example above we specify that ``Y`` can be any subclass of<br>Iterable with elements of type ``X``, as long as the return type of<br>``filter()`` will be the same as the type of the ``input``<br>argument.<br><br>.. FIXME: Explain more about how this works.<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, to be resolved later.  For<br>example, instead of writing::<br><br>  def notify_by_email(employees: Set[Employee]): ...<br><br>one might write::<br><br>  def notify_by_email(employees: 'Set[Employee]'): ...<br><br>.. FIXME: Rigorously define this.  Defend it, or find an alternative.<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]]):<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 subclasses, ``T2`` and<br>any of its subclasses, 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]): ...<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]): ...<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): ...<br><br>.. FIXME: Is this really a good idea?<br><br>A special kind of union type is ``Any``, a class that responds<br>``True`` to ``issubclass`` of any class.  This lets the user<br>explicitly state that there are no constraints on the type of a<br>specific argument or return value.<br><br><br>Platform-specific type checking<br>-------------------------------<br><br>In some cases the typing information will depend on the platform that<br>the program is being executed on.  To enable specifying those<br>differences, simple conditionals can be used::<br><br>  from typing import PY2, WINDOWS<br><br>  if PY2:<br>      text = unicode<br>  else:<br>      text = str<br><br>  def f() -> text: ...<br><br>  if WINDOWS:<br>      loop = ProactorEventLoop<br>  else:<br>      loop = UnixSelectorEventLoop<br><br>Arbitrary literals defined in the form of ``NAME = True`` will also be<br>accepted by the type checker to differentiate type resolution::<br><br>  DEBUG = False<br>  ...<br>  if DEBUG:<br>      class Tracer:<br>          <verbose implementation><br>  else:<br>      class Tracer:<br>          <dummy implementation><br><br>For the purposes of type hinting, the type checker assumes ``__debug__``<br>is set to ``True``, in other words the ``-O`` command-line option is not<br>used while type checking.<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 a<br>static type checker.  However, since type hinting annotations have no<br>run time behavior (other than evaluation of the annotation expression<br>and storing annotations in the ``__annotations__`` attribute of the<br>function object), this does not make the program incorrect -- it just<br>makes it issue warnings when a static analyzer is used.<br><br>To mark portions of the program that should not be covered by type<br>hinting, use the following:<br><br>* a ``@no_type_checks`` decorator on classes and functions<br><br>* a ``# type: ignore`` comment on arbitrary lines<br><br>.. FIXME: should we have a module-wide comment as well?<br><br><br>Type Hints on Local and Global Variables<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><br>In the case where type information for a local variable is needed before<br>if was declared, an ``Undefined`` placeholder might be used::<br><br>  from typing import Undefined<br><br>  x = Undefined   # type: List[Employee]<br>  y = Undefined(int)<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><br>Explicit raised exceptions<br>==========================<br><br>No support for listing explicitly raised exceptions is being defined by<br>this PEP.  Currently the only known use case for this feature is<br>documentational, in which case the recommendation is to put this<br>information in a docstring.<br><br><br>The ``typing`` package<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>package in the standard library is introduced called ``typing``.  It<br>holds a set of classes representing builtin types with generics, namely:<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>* Tuple, used as ``Tuple[index0_type, index1_type, ...]``.<br>  Arbitrary-length tuples might be expressed using ellipsis, in which<br>  case the following arguments are considered the same type as the last<br>  defined type on the tuple.<br><br>It also introduces factories and helper members needed to express<br>generics and union types:<br><br>* Any, used as ``def get(key: str) -> Any: ...``<br><br>* Union, used as ``Union[Type1, Type2, Type3]``<br><br>* TypeVar, used as ``X = TypeVar('X', Type1, Type2, Type3)`` or simply<br>  ``Y = TypeVar('Y')``<br><br>* Undefined, used as ``local_variable = Undefined # type: List[int]`` or<br>  ``local_variable = Undefined(List[int])`` (the latter being slower<br>  during runtime)<br><br>* Callable, used as ``Callable[[Arg1Type, Arg2Type], ReturnType]``<br><br>* AnyArgs, used as ``Callable[AnyArgs, ReturnType]``<br><br>* AnyStr, equivalent to ``TypeVar('AnyStr', str, bytes)``<br><br>All abstract base classes available in ``collections.abc`` are<br>importable from the ``typing`` package, with added generics support:<br><br>* ByteString<br><br>* Callable<br><br>* Container<br><br>* Hashable<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 as ``AbstractSet``. This name change was required because ``Set``<br>  in the ``typing`` module means ``set()`` with generics.<br><br>* Sized<br><br>* ValuesView<br><br>* Mapping<br><br>The library includes literals for platform-specific type hinting:<br><br>* PY2<br><br>* PY3, equivalent to ``not PY2``<br><br>* WINDOWS<br><br>* UNIXOID, equivalent to ``not WINDOWS``<br><br>The following types are available in the ``<a href="http://typing.io">typing.io</a>`` module:<br><br>* IO<br><br>* BinaryIO<br><br>* TextIO<br><br>The following types are provided by the ``<a href="http://typing.re">typing.re</a>`` module:<br><br>* Match and Pattern, types of ``re.match()`` and ``re.compile()``<br>  results<br><br>As a convenience measure, types from ``<a href="http://typing.io">typing.io</a>`` and ``<a href="http://typing.re">typing.re</a>`` are<br>also available in ``typing`` (quoting Guido, "There's a reason those<br>modules have two-letter names.").<br><br><br>The place of the ``typing`` module in the standard library<br>----------------------------------------------------------<br><br>.. FIXME: complete this section<br><br><br>Usage Patterns<br>==============<br><br>The main use case of type hinting is static analysis using an external<br>tool without executing the analyzed program.  Existing tools used for<br>that purpose like ``pyflakes`` [pyflakes]_ or ``pylint`` [pylint]_<br>might be extended to support type checking.  New tools, like mypy's<br>``mypy -S`` mode, can be adopted specifically for this purpose.<br><br>Type checking based on type hints is understood as a best-effort<br>mechanism.  In other words, whenever types are not annotated and cannot<br>be inferred, the type checker considers such code valid.  Type errors<br>are only reported in case of explicit or inferred conflict.  Moreover,<br>as a mechanism that is not tied to execution of the code, it does not<br>affect runtime behaviour.  In other words, even in the case of a typing<br>error, the program will continue running.<br><br>The implementation of a type checker, whether linting source files or<br>enforcing type information during runtime, is out of scope for this PEP.<br><br>.. FIXME: Describe stub modules.<br><br>.. FIXME: Describe run-time behavior of generic types.<br><br><br>Existing Approaches<br>===================<br><br>PEP 482 lists existing approaches in Python and other languages.<br><br><br>Is type hinting Pythonic?<br>=========================<br><br>Type annotations provide important documentation for how a unit of code<br>should be used.  Programmers should therefore provide type hints on<br>public APIs, namely argument and return types on functions and methods<br>considered public.  However, because types of local and global variables<br>can be often inferred, they are rarely necessary.<br><br>The kind of information that type hints hold has always been possible to<br>achieve by means of docstrings.  In fact, a number of formalized<br>mini-languages for describing accepted arguments have evolved.  Moving<br>this information to the function declaration makes it more visible and<br>easier to access both at runtime and by static analysis.  Adding to that<br>the notion that “explicit is better than implicit”, type hints are<br>indeed *Pythonic*.<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, and Radomir Dopieralski.<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>.. [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><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 clear="all"><div><br>-- <br><div>--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div></div>