Skip to main content
  1. posts/

Annotations and Type Checking in Python

·3 mins

Python is a dynamically typed programming language. This means that type checking is done at run-time. PEP 484 introduced type hints, which makes it possible to add type hints to variables and function signatures.

In this article, we will be looking at how to add annotations and type checking to our Python code.

Adding annotations to a Python function #

Let us begin by considering the change required to annotate a basic Python function.

Imagine a function say_hello that takes and returns a string. Without hints, this function would look like this:

def say_hello(name):
    return "Hello " + name

It can be annotated as follows:

def say_hello(name: str) -> str:
    return "Hello " + name

Type aliases #

In this section, I will show you how to use the typings module to create type aliases.

A type alias is a name that refers to a previously defined type.

To define a function itemize_names that takes a list of names of length n and returns a new list with names numbered from 1 to n. An implementation of the function can be found below:

def itemize_names(names):
    return [f"{pos + 1}. {name}" for pos, name in enumerate(names)]

To annotate the function, an alias can be created for names:

from typing import List

NameList = List[str]

def itemize_names(names: NameList) -> NameList:
    return [f"{pos + 1}. {name}" for pos, name in enumerate(names)]

The typing module provides support for so much more, such as:

  • Creating a new type
  • Annotating a function that takes a callback
  • Generics

You can find the documentation here to learn how to add type hints to your Python code.

Type checking #

While you can add type annotations to your code, the Python runtime does not enforce type annotations. In this section of the article, I will outline how to enforce type checking on your annotated Python code.

To demonstrate, the say_hello function defined earlier can be re-written, incorrectly, like this without producing any change in functionality.

def say_hello(name: str) -> int:
    return "Hello " + name

You will also not get a warning from Python.

To enforce type checks, there are a number of static type checkers available. I would be using mypy.

Let’s install mypy to get those type checks we need. You can install mypy with this command:

$ python3 -m pip install mypy

To type check our say_hello function, let’s say it is contained in a say_hello.py file:

$ mypy say_hello.py 

say_hello.py:2: error: Incompatible return value type (got "str", expected "int")
Found 1 error in 1 file (checked 1 source file)

Let’s fix the error by changing the expected return type back to str and type check our file again:

$ mypy say_hello.py

Success: no issues found in 1 source file

The mypy documentation provides all the information required on how to use mypy in your projects.

Conclusion #

Python is a dynamically typed programming language and does not enforce type checking out of the box. In this article, I have written about how to annotate Python code and enforce type checking at runtime.