Type annotations¶
The meaning of annotations¶
The type system 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 annotation slots with classes:
def greeting(name: str) -> str:
return 'Hello ' + name
This states that the expected type of the name
argument is
str
. Analogically, the expected return type is str
.
Expressions whose type is assignable to a specific argument type are also accepted for that argument. Similarly, an expression whose type is assignable to the annotated return type can be returned from the function.
Any function without annotations can be treated as having Any annotations on all arguments and the return type. Type checkers may also optionally infer more precise types for missing annotations.
Type checkers may choose to entirely ignore (not type check) the bodies of functions with no annotations, but this behavior is not required.
It is recommended but not required that checked functions have
annotations for all arguments and the return type. For a checked
function, the default annotation for arguments and for the return type
is Any
. An exception is the first argument of instance and
class methods. If it is not annotated, then it is assumed to have the
type of the containing class for instance methods, and a type object
type corresponding to the containing class object for class methods.
For example, in class A
the first argument of an instance method
has the implicit type A
. In a class method, the precise type of
the first argument cannot be represented using the available type
notation.
(Note that the return type of __init__
ought to be annotated with
-> None
. The reason for this is subtle. If __init__
assumed
a return annotation of -> None
, would that mean that an
argument-less, un-annotated __init__
method should still be
type-checked? Rather than leaving this ambiguous or introducing an
exception to the exception, we simply say that __init__
ought to
have a return annotation; the default behavior is thus the same as for
other methods.)
A type checker is expected to check the body of a checked function for consistency with the given annotations. The annotations may also be used to check correctness of calls appearing in other checked functions.
Type checkers are expected to attempt to infer as much information as
necessary. The minimum requirement is to handle the builtin
decorators @property
, @staticmethod
and @classmethod
.
Type and annotation expressions¶
The terms type expression and annotation expression denote specific subsets of Python expressions that are used in the type system. All type expressions are also annotation expressions, but not all annotation expressions are type expressions.
A type expression is any expression that validly expresses a type. Type expressions are always acceptable in annotations and also in various other places. Specifically, type expressions are used in the following locations:
In a type annotation (always as part of an annotation expression)
The first argument to cast()
The second argument to assert_type()
The bounds and constraints of a
TypeVar
(whether created through the old syntax or the native syntax in Python 3.12)The definition of a type alias (whether created through the
type
statement, the old assignment syntax, or theTypeAliasType
constructor)The type arguments of a generic class (which may appear in a base class or in a constructor call)
The definitions of fields in the functional forms for creating TypedDict and NamedTuple types
The base type in the definition of a NewType
An annotation expression is an expression that is acceptable to use in an annotation context (a function parameter annotation, function return annotation, or variable annotation). Generally, an annotation expression is a type expression, optionally surrounded by one or more type qualifiers or by Annotated. Each type qualifier is valid only in some contexts. Note that while annotation expressions are the only expressions valid as type annotations in the type system, the Python language itself makes no such restriction: any expression is allowed.
Annotations must be valid expressions that evaluate without raising exceptions at the time the function is defined (but see String annotations).
The following grammar describes the allowed elements of type and annotation expressions:
annotation_expression ::= <Required> '['annotation_expression
']' | <NotRequired> '['annotation_expression
']' | <ReadOnly> '['annotation_expression
']' | <ClassVar> '['annotation_expression
']' | <Final> '['annotation_expression
']' | <InitVar> '['annotation_expression
']' | <Annotated> '['annotation_expression
',' expression (',' expression)* ']' | <TypeAlias> (valid only in variable annotations) |unpacked
(valid only for *args annotations) | <Unpack> '[' name ']' (where name refers to an in-scope TypedDict; valid only in **kwargs annotations) |string_annotation
(must evaluate to a validannotation_expression
) | name '.' 'args' (where name must be an in-scope ParamSpec; valid only in *args annotations) | name '.' 'kwargs' (where name must be an in-scope ParamSpec; valid only in **kwargs annotations) |type_expression
type_expression ::= <Any> | <Self> (valid only in some contexts) | <LiteralString> | <NoReturn> | <Never> | <None> | name (where name must refer to a valid in-scope class, type alias, or TypeVar) | name '[' (maybe_unpacked
|type_expression_list
) (',' (maybe_unpacked
|type_expression_list
))* ']' (thetype_expression_list
form is valid only when specializing a ParamSpec) | name '[' '(' ')' ']' (denoting specialization with an empty TypeVarTuple) | <Literal> '[' expression (',' expression) ']' (see documentation for Literal for restrictions) |type_expression
'|'type_expression
| <Optional> '['type_expression
']' | <Union> '['type_expression
(','type_expression
)* ']' | <type> '[' <Any> ']' | <type> '[' name ']' (where name must refer to a valid in-scope class or TypeVar) | <Callable> '[' '...' ','type_expression
']' | <Callable> '[' name ','type_expression
']' (where name must be a valid in-scope ParamSpec) | <Callable> '[' <Concatenate> '[' (type_expression
',')+ (name | '...') ']' ','type_expression
']' (where name must be a valid in-scope ParamSpec) | <Callable> '[' '['maybe_unpacked
(','maybe_unpacked
)* ']' ','type_expression
']' |tuple_type_expression
| <Annotated> '['type_expression
',' expression (',' expression)* ']' | <TypeGuard> '['type_expression
']' (valid only in some contexts) | <TypeIs> '['type_expression
']' (valid only in some contexts) |string_annotation
(must evaluate to a validtype_expression
) maybe_unpacked ::=type_expression
|unpacked
unpacked ::= '*'unpackable
| <Unpack> '['unpackable
']' unpackable ::=tuple_type_expression
` | name (where name must refer to an in-scope TypeVarTuple) tuple_type_expression ::= <tuple> '[' '(' ')' ']' (representing an empty tuple) | <tuple> '['type_expression
',' '...' ']' (representing an arbitrary-length tuple) | <tuple> '['maybe_unpacked
(','maybe_unpacked
)* ']' string_annotation ::= string (must be a string literal that is parsable as Python code; see "String annotations") type_expression_list ::= '['type_expression
(','type_expression
)* ']' | '[' ']'
Notes:
The grammar assumes the code has already been parsed as Python code, and loosely follows the structure of the AST. Syntactic details like comments and whitespace are ignored.
<Name>
refers to a special form. Most special forms must be imported fromtyping
ortyping_extensions
, except forNone
,InitVar
,type
, andtuple
. The latter two have aliases intyping
:typing.Type
andtyping.Tuple
.InitVar
must be imported fromdataclasses
.Callable
may be imported from eithertyping
orcollections.abc
. Special forms may be aliased (e.g.,from typing import Literal as L
), and they may be referred to by a qualified name (e.g.,typing.Literal
). There are other special forms that are not acceptable in any annotation or type expression, includingGeneric
,Protocol
, andTypedDict
.Any leaf denoted as
name
may also be a qualified name (i.e.,module '.' name
orpackage '.' module '.' name
, with any level of nesting).Comments in parentheses denote additional restrictions not expressed in the grammar, or brief descriptions of the meaning of a construct.
String annotations¶
When a type hint cannot be evaluated at runtime, that definition may be expressed as a string literal, to be resolved later.
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:
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
To address this, we write:
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, '', 'eval')
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 expression grammar.
If a triple quote is used, the string should be parsed as though it is implicitly surrounded by parentheses. This allows newline characters to be used within the string literal:
value: """
int |
str |
list[Any]
"""
It is allowable to use string literals as part of a type hint, for example:
class Tree:
...
def leaves(self) -> list['Tree']:
...
A common use for forward references is when e.g. Django models are needed in the signatures. Typically, each model is in a separate file, and has methods taking arguments whose type involves other models. Because of the way circular imports work in Python, it is often not possible to import all the needed models directly:
# File models/a.py
from models.b import B
class A(Model):
def foo(self, b: B): ...
# File models/b.py
from models.a import A
class B(Model):
def bar(self, a: A): ...
# File main.py
from models.a import A
from models.b import B
Assuming main is imported first, this will fail with an ImportError at
the line from models.a import A
in models/b.py, which is being
imported from models/a.py before a has defined class A. The solution
is to switch to module-only imports and reference the models by their
_module_._class_ name:
# File models/a.py
from models import b
class A(Model):
def foo(self, b: 'b.B'): ...
# File models/b.py
from models import a
class B(Model):
def bar(self, a: 'a.A'): ...
# File main.py
from models.a import A
from models.b import B
Annotating generator functions and coroutines¶
The return type of generator functions can be annotated by
the generic type Generator[yield_type, send_type,
return_type]
provided by typing.py
module:
def echo_round() -> Generator[int, float, str]:
res = yield 0
while res:
res = yield round(res)
return 'OK'
Coroutines introduced in PEP 492 are annotated with the same syntax as
ordinary functions. However, the return type annotation corresponds to the
type of await
expression, not to the coroutine type:
async def spam(ignored: int) -> str:
return 'spam'
async def foo() -> None:
bar = await spam(42) # type is str
The generic ABC collections.abc.Coroutine
can be used
to specify awaitables that also support
send()
and throw()
methods. The variance and order of type variables
correspond to those of Generator
, namely Coroutine[T_co, T_contra, V_co]
,
for example:
from collections.abc import Coroutine
c: Coroutine[list[str], str, int]
...
x = c.send('hi') # type is list[str]
async def bar() -> None:
x = await c # type is int
The generic ABCs Awaitable
,
AsyncIterable
, and AsyncIterator
can be used for situations where more precise
types cannot be specified:
def op() -> collections.abc.Awaitable[str]:
if cond:
return spam(42)
else:
return asyncio.Future(...)
Annotating instance and class methods¶
In most cases the first argument of class and instance methods does not need to be annotated, and it is assumed to have the type of the containing class for instance methods, and a type object type corresponding to the containing class object for class methods. In addition, the first argument in an instance method can be annotated with a type variable. In this case the return type may use the same type variable, thus making that method a generic function. For example:
T = TypeVar('T', bound='Copyable')
class Copyable:
def copy(self: T) -> T:
# return a copy of self
class C(Copyable): ...
c = C()
c2 = c.copy() # type here should be C
The same applies to class methods using type[]
in an annotation
of the first argument:
T = TypeVar('T', bound='C')
class C:
@classmethod
def factory(cls: type[T]) -> T:
# make a new instance of cls
class D(C): ...
d = D.factory() # type here should be D
Note that some type checkers may apply restrictions on this use, such as requiring an appropriate upper bound for the type variable used (see examples).