Historical and deprecated features¶
Over the course of the development of the Python type system, severalchanges were made to the Python grammar and standard library to make iteasier to use the type system. This specification aims to use the moremodern syntax in all examples, but type checkers should generally supportthe older alternatives and treat them as equivalent.
This section lists all of these cases.
Type comments¶
No first-class syntax support for explicitly marking variables as beingof a specific type existed when the type system was first designed.To help with type inference incomplex cases, a comment of the following format may be used:
x=[]# type: list[Employee]x,y,z=[],[],[]# type: list[int], list[int], list[str]x,y,z=[],[],[]# type: (list[int], list[int], list[str])a,b,*c=range(5)# type: float, float, list[float]x=[1,2]# type: list[int]
Type comments should be put on the last line of the statement thatcontains the variable definition.
These should be treated as equivalent to annotating the variablesusingPEP 526 variable annotations:
x:list[Employee]=[]x:list[int]y:list[int]z:list[str]x,y,z=[],[],[]a:floatb:floatc:list[float]a,b,*c=range(5)x:list[int]=[1,2]
Type comments can also be placed onwith statements andfor statements, right after the colon.
Examples of type comments onwith andfor statements:
withfrobnicate()asfoo:# type: int# Here foo is an int...forx,yinpoints:# type: float, float# Here x and y are floats...
In stubs it may be useful to declare the existence of a variablewithout giving it an initial value. This can be done usingPEP 526variable annotation syntax:
fromtypingimportIOstream:IO[str]
The above syntax is acceptable in stubs for all versions of Python.However, in non-stub code for versions of Python 3.5 and earlierthere is a special case:
fromtypingimportIOstream=None# type: IO[str]
Type checkers should not complain about this (despite the valueNone not matching the given type), nor should they change theinferred type to...|None. Theassumption here is that other code will ensure that the variable isgiven a value of the proper type, and all uses can assume that thevariable has the given type.
Type comments on function definitions¶
Some tools may want to support type annotations in code that must becompatible with Python 2.7. For this purpose function annotations can be placed ina#type: comment. Such a comment must be placed immediatelyfollowing the function header (before the docstring). An example: thefollowing Python 3 code:
defembezzle(self,account:str,funds:int=1000000,*fake_receipts:str)->None:"""Embezzle funds from account using fake receipts."""<codegoeshere>
is equivalent to the following:
defembezzle(self,account,funds=1000000,*fake_receipts):# type: (str, int, *str) -> None"""Embezzle funds from account using fake receipts."""<codegoeshere>
Note that for methods, no type is needed forself.
For an argument-less method it would look like this:
defload_cache(self):# type: () -> bool<code>
Sometimes you want to specify the return type for a function or methodwithout (yet) specifying the argument types. To support thisexplicitly, the argument list may be replaced with an ellipsis.Example:
defsend_email(address,sender,cc,bcc,subject,body):# type: (...) -> bool"""Send an email message. Return True if successful."""<code>
Sometimes you have a long list of parameters and specifying theirtypes in a single#type: comment would be awkward. To this endyou may list the arguments one per line and add a#type: commentper line after an argument’s associated comma, if any.To specify the return type use the ellipsis syntax. Specifying the returntype is not mandatory and not every argument needs to be given a type.A line with a#type: comment should contain exactly one argument.The type comment for the last argument (if any) should precede the closeparenthesis. Example:
defsend_email(address,# type: Union[str, List[str]]sender,# type: strcc,# type: Optional[List[str]]bcc,# type: Optional[List[str]]subject='',body=None# type: List[str]):# type: (...) -> bool"""Send an email message. Return True if successful."""<code>
Notes:
Tools that support this syntax should support it regardless of thePython version being checked. This is necessary in order to supportcode that straddles Python 2 and Python 3.
It is not allowed for an argument or return value to have botha type annotation and a type comment.
When using the short form (e.g.
#type:(str,int)->None)every argument must be accounted for, except the first argument ofinstance and class methods (those are usually omitted, but it’sallowed to include them).The return type is mandatory for the short form. If in Python 3 youwould omit some argument or the return type, the Python 2 notationshould use
Any.When using the short form, for
*argsand**kwds, put 1 or 2stars in front of the corresponding type annotation. (As withPython 3 annotations, the annotation here denotes the type of theindividual argument values, not of the tuple/dict that you receiveas the special argument valueargsorkwds.)Like other type comments, any names used in the annotations must beimported or defined by the module containing the annotation.
When using the short form, the entire annotation must be one line.
The short form may also occur on the same line as the closeparenthesis, e.g.:
defadd(a,b):# type: (int, int) -> intreturna+b
Misplaced type comments will be flagged as errors by a type checker.If necessary, such comments could be commented twice. For example:
deff():'''Docstring'''# type: () -> None # Error!defg():'''Docstring'''# # type: () -> None # This is OK
When checking Python 2.7 code, type checkers should treat theint andlong types as equivalent. For parameters typed asText, arguments oftypestr as well asunicode should be acceptable.
Positional-only parameters¶
Some functions are designed to take their arguments only positionally,and expect their callers never to use the argument’s name to providethat argument by keyword. Before Python 3.8 (PEP 570), Python didnot provide a way to declare positional-only parameters.
To support positional-only parameters in code that must remain compatiblewith older versions of Python, type checkers should support the followingspecial case: all parameters with names that begin but don’t end with__are assumed to be positional-only:
deff(__x:int,__y__:int=0)->None:...f(3,__y__=1)# This call is fine.f(__x=3)# This call is an error.
Consistent withPEP 570 syntax, positional-only parameters cannot appearafter parameters that accept keyword arguments. Type checkers should enforcethis requirement:
defg(x:int,__y:int)->None:...# Type error
Generics in standard collections¶
Before Python 3.9 (PEP 585), standard library generic types likelist could not be parameterized at runtime (i.e.,list[int]would throw an error). Therefore, thetyping module providedgeneric aliases for major builtin and standard library types (e.g.,typing.List[int]).
In each of these cases, type checkers should treat the library typeas equivalent to the alias in thetyping module. This includes:
listandtyping.Listdictandtyping.Dictsetandtyping.Setfrozensetandtyping.FrozenSettupleandtyping.Tupletypeandtyping.Typecollections.dequeandtyping.Dequecollections.defaultdictandtyping.DefaultDictcollections.OrderedDictandtyping.OrderedDictcollections.Counterandtyping.Countercollections.ChainMapandtyping.ChainMapcollections.abc.Awaitableandtyping.Awaitablecollections.abc.Coroutineandtyping.Coroutinecollections.abc.AsyncIterableandtyping.AsyncIterablecollections.abc.AsyncIteratorandtyping.AsyncIteratorcollections.abc.AsyncGeneratorandtyping.AsyncGeneratorcollections.abc.Iterableandtyping.Iterablecollections.abc.Iteratorandtyping.Iteratorcollections.abc.Generatorandtyping.Generatorcollections.abc.Reversibleandtyping.Reversiblecollections.abc.Containerandtyping.Containercollections.abc.Collectionandtyping.Collectioncollections.abc.Callableandtyping.Callablecollections.abc.Setandtyping.AbstractSet(note the change in name)collections.abc.MutableSetandtyping.MutableSetcollections.abc.Mappingandtyping.Mappingcollections.abc.MutableMappingandtyping.MutableMappingcollections.abc.Sequenceandtyping.Sequencecollections.abc.MutableSequenceandtyping.MutableSequencecollections.abc.ByteStringandtyping.ByteStringcollections.abc.MappingViewandtyping.MappingViewcollections.abc.KeysViewandtyping.KeysViewcollections.abc.ItemsViewandtyping.ItemsViewcollections.abc.ValuesViewandtyping.ValuesViewcontextlib.AbstractContextManagerandtyping.ContextManager(note the change in name)contextlib.AbstractAsyncContextManagerandtyping.AsyncContextManager(note the change in name)re.Patternandtyping.Patternre.Matchandtyping.Match
The generic aliases in thetyping module are considered deprecatedand type checkers may warn if they are used.
Union andOptional¶
Before Python 3.10 (PEP 604), Python did not support the| operatorfor creating unions of types. Therefore, thetyping.Unionspecial form can alsobe used to create union types. Type checkers should treat the two forms as equivalent.
In addition, theOptionalspecial form is equivalent to a union withNone.
Examples:
int|stris the same asUnion[int,str]int|str|rangeis the same asUnion[int,str,range]int|Noneis the same asOptional[int]andUnion[int,None]
Unpack¶
PEP 646, which introducedTypeVarTuple into Python 3.11, also made two grammarchanges to support use of variadic generics, allowing use of the* operator inindex operations and in*args annotations. TheUnpack[] operator was added tosupport equivalent semantics on older Python versions. It should be treated as equivalentto the* syntax. In particular, the following are equivalent:
A[*Ts]is the same asA[Unpack[Ts]]deff(*args:*Ts):...is the same asdeff(*args:Unpack[Ts]):...