Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to hundreds of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set the default subtitles language in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.


Give Feedback

In this lesson, you’ll learn about annotations in Python. Annotations were introduced in Python 3.0 originally without any specific purpose. They were simply a way to associate arbitrary expressions to function arguments and return values.

Years later, PEP 484 defined how to add type hints to your Python code, based off work that Jukka Lehtosalo had done on his Ph.D. project, Mypy. The main way to add type hints is using annotations. As type checking is becoming more and more common, this also means that annotations should mainly be reserved for type hints.

Function Annotations

For functions, you can annotate arguments and the return value. This is done as follows:

def func(arg: arg_type, optarg: arg_type = default) -> return_type:

For arguments, the syntax is argument: annotation, while the return type is annotated using -> annotation. Note that the annotation must be a valid Python expression.

When running the code, you can also inspect the annotations. They are stored in a special .__annotations__ attribute on the function:

>>> import math

>>> def circumference(radius: float) -> float:
...     return 2 * math.pi * radius
>>> circumference.__annotations__
{'radius': <class 'float'>, 'return': <class 'float'>}
>>> circumference(1.23)

Sometimes you might be confused by how Mypy is interpreting your type hints. For those cases, there are special Mypy expressions: reveal_type() and reveal_locals(). You can add these to your code before running Mypy, and Mypy will dutifully report which types it has inferred. For example, save the following code to


import math

radius = 1
circumference = 2 * math.pi * radius

Next, run this code through Mypy:

$ mypy error: Revealed type is 'builtins.float' error: Revealed local types are: error: circumference: builtins.float error: radius:

Remember that the expressions reveal_type() and reveal_locals() are for troubleshooting in Mypy. If you were to run the Python script interpreter, it would crash with a NameError:

$ python3
Traceback (most recent call last):
  File "", line 4, in <module>
NameError: name 'reveal_type' is not defined

Variable Annotations

In the definition of circumference() in the previous section, you only annotated the arguments and the return value. You did not add any annotations inside the function body. More often than not, this is enough.

However, sometimes the type checker needs help in figuring out the types of variables as well. Variable annotations were defined in PEP 526 and introduced in Python 3.6. The syntax is the same as for function argument annotations. Annotations of variables are stored in the module level __annotations__ dictionary:

>>> pi: float = 3.142
>>> def circumference(radius: float) -> float:
>>>     return 2 * pi * radius

>>> circumference.__annotations__
{'radius': <class 'float'>, 'return': <class 'float'>}

>>> __annotations__
{'pi': <class 'float'>}

>>> circumference(1)
>>> nothing: str

>>> nothing
Traceback (most recent call last):
  File "<input>", line 1, in <module>
NameError: name 'nothing' is not defined
>>> __annotations__
{'pi': <class 'float'>, 'nothing':<class 'str'>}

Become a Member to join the conversation.