Skip to content

5. Type

Python is a dynamically typed language. This means that you don't have to specify the type of a variable when you declare it. While this is one of the advantages of Python - you can write code faster, easier and more flexibly - it can also lead to problems. Because you don't know what type a variable is at runtime, you can run into problems if you try to use a variable in a way that is incompatible with its type. This can lead to bugs that are difficult to find and fix.

PEP 484 – Type Hints introduced type hints to Python, which have been accepted with Python 3.5.

Normal Python code:

def greeting(name):
    return 'Hello ' + name

Staticly typed Python code:

def greeting(name: str) -> str:
    return 'Hello ' + name

Python's type hints have no direct effect on the runtime performance of your code. They are designed to be completely optional and ignored during execution. So even if they are typed, you could pass a different type to the function. However, similar to formatters and linters, there are static type checkers that will check this for you. It is recommended to use type hints, as they help you to write correct and self-documenting code. An existing code base can also be typed step by step.

Example

See demo project:

Before | After | Diff

Tools

Static type checkers

There are different type checkers, but they will all align to PEP 484. However, they are all different and vary in speed. If you don't know where to start, have a look at mypy. If you have a really large code base, you might want to check one of the others.

mypy

mypy is the most popular static type checker for Python. It was the first major type checker for Python and is widely used. Also, the default checks are not too strict, so you can start using it in an existing code base without too much effort.

A simple example of what mypy will check:

# my_file.py
def greeting(name: str) -> str:
    return 'Hello ' + name

greeting(3)
greeting(b'Alice')
greeting("World!")

def bad_greeting(name: str) -> str:
    return 'Hello ' * name
To run mypy, you can use the following command:
$ mypy my_file.py
my_file.py:5: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"  [arg-type]
my_file.py:6: error: Argument 1 to "greeting" has incompatible type "bytes"; expected "str"  [arg-type]
my_file.py:10: error: Unsupported operand types for * ("str" and "str")  [operator]
Found 3 errors in 1 file (checked 1 source file)

Check the mypy documentation for more informations.

pyright

pyright is a static type checker for Python created by Microsoft. It is written in TypeScript and runs on Node.js. It is designed to be fast and efficient and might run faster on large code bases than mypy. And since it is developed by Microsoft, it has good support for Visual Studio Code.

Check the pyright documentation for more informations.

pytype

pytype is a static type checker for Python created by Google.

Check the pytype documentation for more informations.

pyre

pyre is a static type checker for Python created by Facebook.

Check the pyre documentation for more informations

Runtime type checkers

There are also runtime type checkers that check the types of variables at runtime. These libraries can also do normal data validation. This is a more advanced topic and does not just sit on top of PEP 484. But for the sake of completeness, there are a few libraries that might be worth looking at.

pydantic

pydantic is a data validation and settings management library for Python. It uses Python type hints to validate the data at runtime. It is widely used in the FastAPI framework.

Check the pydantic documentation s.

attrs

attrs is a library for creating classes without writing boilerplate code. It is similar to dataclasses, but has more features and is more flexible. It also uses Python type hints to validate the data at runtime.

Check the attrs documentation for more informations.

Resources