The main goal of type annotations is to open up Python code to easier static analysis and refactoring, potential runtime type checking, and (perhaps, in some contexts) code generation utilizing type information. These were introduced in PEP 484.
In this regards, static type checking is the most important. It allows support for off-line third-party type checkers, such as Mypy.
Purpose of annotations
typing module in Python 3.6 contains many definitions that are useful in statically typed code. For instance, the
Any type is used by default for every argument and return type of a function. This is all in regards to a checked function. If a function is to be ignored by a static type checker, the decorator
@no_type_check should be used. This function will now be treated as having no type annotations.
An example following the type annotations is shown below:
def scale(scalar: int, number: int) -> int: return scalar * number
This states that the expected type of the
number argument is
int, respectively. Analogically, the expected return type is also
The acceptable type hints that may be used are:
Callable, all types exported from
Dict ), type variables, and type aliases.
Using type aliases
Type aliases can be defined by using simple variable assignments:
Temperature = float def forecast(temperature: Temperature, day: int) -> str: ...
Creating your own types
In Python 3.5 a new function was introduced called
NewType. This allows the programmer to create distinct types:
from typing import NewType UserId = NewType('UserId', int) some_id = UserId(356)
Static type checking using Mypy
When a script is run with a standard Python interpreter, the type annotations are treated primarily as comments. Using
mypy, common code bugs can be found and it checks the code for proper return types etc. As
mypy is a static analyzer, it does not interfere when running the program. A function without a type annotation is considered dynamically typed.
mypy for checking a class method I wrote:
@classmethod def parse_file_properties(cls, properties: str) -> OrderedDict: properties = properties.split('\n') list_properties =  for property in properties: key_value = property.split('=') try: list_properties.append((key_value.strip(), key_value.strip())) except IndexError: # The case where a property contains comment or a blank line pass return OrderedDict(list_properties)
This function takes in a
= separated string, parses it using
split(), and returns it as an ordered dictionary. When I run
mypy from a terminal, issuing the command
python -m mypy hips/tiles, I get no error or warning, so my type annotations were correct.
However, If I change the function header to:
def parse_file_properties(cls, properties: int) -> OrderedDict:
I get this error message:
hips/tiles/description.py:61: error: "int" has no attribute "split"
The illustration below shows the basic workflow of static type checking: