Python type annotations
Type annotations
Since Python there is support for annotations of variable types, class fields, arguments, and return values of functions. However it breaks backwards compatibility. If you want to keep it, write types in docstrings.
Basics
Variable annotations are written with a colon after the identifier. This can be followed by value initialization.
1
2price: int = 5
title: "str"Function parameters are annotated in the same way as variables, and the return value is specified after the arrow -> and before the trailing colon.
1
2
3def func(a: int, b: float) -> str:
a: str = f"{a}, {b}"
return aFor class fields, annotations must be specified explicitly when the class is defined. However, analyzers can automatically infer them based on the
__init__
method, but in this case, they will not be available at runtime:1
2
3
4
5
6
7
8
9class Book:
title: "str"
author: str
def __init__(self, title: str, author: str) -> None:
self.title = title
self.author = author
b: Book = Book(title="Fahrenheit 451", author="Bradbury")
Built-in types (sub-modules)
Optional
1 | amount: int |
Any
1 | # do not restrict possible types |
Union
1 | # allow only some types |
Collections
See PEP484 - Generics.
Generics
1
2
3
4
5
6from typing import Mapping, Set
def notify_by_email(
employees: Set[Employee],
overrides: Mapping[str, str]
) -> None: ...Generics with parameters
1
2
3
4
5
6
7
8from typing import Sequence, TypeVar
# Declare type variable
T = TypeVar('T')
# Generic function
def first(l: Sequence[T]) -> T:
return l[0]User defined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25from typing import TypeVar, Generic, Iterable
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
def __init__(self, value: T, name: str, logger: Logger) -> None:
self.name = name
self.logger = logger
self.value = value
def set(self, new: T) -> None:
self.log('Set ' + repr(self.value))
self.value = new
def get(self) -> T:
self.log('Get ' + repr(self.value))
return self.value
def log(self, message: str) -> None:
self.logger.info('{}: {}'.format(self.name, message))
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
for var in vars:
var.set(0)
Lists
1 | titles: List[str] = ["hello", "world"] |
Note: there are similar annotations for sets:
typing.Set
andtyping.FrozenSet
.
Tuples
1 | price_container: Tuple[int] = (1,) |
Dictionaries
1 | # key and type are specified separate |
There is also
typing.DefaultDict
andtyping.OrderedDict
Function execution results
Function returns nothing:
1
2
3
4
5
6
7
8
9
10def nothing(a: int) -> None:
if a == 1:
return
elif a == 2:
return
elif a == 3:
# No return value expected
return ""
else:
passFunction never returns control (e.g.
sys.exit
)1
2
3def forever() -> NoReturn:
while True:
passGenerator function (its body contains an operator yield)
1
2
3
4
5def generate_two() -> Iterable[int]:
yield 1
yield "2"
# ERROR: Incompatible types in "yield"
# (actual type "str", expected type "int")