Typing#

The Python language is famous for its simplicity. One related trade-off is that it’s a dynamically typed language where the type of variables is not statically defined, but only determined - and may even change - at runtime.

Even though a variable x starts as integer, a simple re-assignment makes it change its type.

x = 1
assert isinstance(x, int)

x = 1.0
assert isinstance(x, float)

x = "1"
assert isinstance(x, str)

Type hints#

It’s a matter of taste if this is considered a bug or a feature. But for sure it may lead to errors if a variable has suddenly an unexpected type. For this reason Python 3.5+ has introduced typing and support for type hints. Python itself does still not enforce any type checks, but at least the language allows for type annotations that can then be parsed and enforced by other tools.

import math
# from __future__ import annotations  # required for Python <= 3.9


def round(x: float) -> int:
    return math.floor(x)

Such type annotations often enhance the clarity and readability of the code, as they provide clear indication of what a function argument is expected to look like.

from datetime import datetime, timedelta


def total_elapsed_seconds_between_datetime_intervals(
    intervals: list[tuple[datetime, datetime]],
) -> float:
    elapsed_seconds = 0.
    for interval in intervals:
        elapsed_seconds += (interval[1] - interval[0]).total_seconds()
    return elapsed_seconds


now = datetime.now()
two_hours_ago = now - timedelta(hours=2)
six_hours_ago = now - timedelta(hours=6)

intervals = [[two_hours_ago, now], [six_hours_ago, two_hours_ago]]

total_seconds = total_elapsed_seconds_between_datetime_intervals(intervals)

assert total_seconds == float((2 + 4) * 3600)

Tip

Even if your project is not using type hints or checks, know how to read type annotations so that you understand other project’s code. Also feel free to adopt type checking gradually in your code base.

Type checks#

Type hints may feel like unnecessary bureaucracy but they can be a powerful tool to improve code quality and catch bugs before they happen. To develop their full potential, type hints should be combined with type checkers, either on the command-line or directly integrated in the code editor. Similar to other static analysis tools like linters, a type checker makes sure all type hints are satisfied before even running the program.

There are a couple of type checkers available to choose from. When using VSCode with the Python extension, the proprietary Pylance dependency already includes type checking. The core functionality is coming from the open-source pyright type checker. This is the recommended choice for most purposes and code editors. An alternative is mypy. Another worthy mention is Pydantic that takes data validation to the next level.

TypedDict example#

As already discussed, the data structures encountered in everyday situations are often a combination of basic data types. Actual objects or dataclasses are the most elegant implementation. But even a pragmatic dictionary can be enhanced with types using typing.TypedDict.

Suppose your research group is expecting a certain data structure to capture measurements. With type hints the checker will immediately warn that the given measurement does not contain all required fields, in this example the name of the experimenter responsible for the data.

from typing import TypedDict
from datetime import datetime


class TemperatureData(TypedDict):
    timestamp: datetime
    experiment_id: int
    experimenter_name: str
    temps: list[float]


temp_measurement: TemperatureData = {
    "timestamp": datetime.now(),
    "experiment_id": 42,
    "temps": [2.734, 2.732, 2.735],
}
$ pyright new_measurement.py
error: [...]
    "experimenter_name" is required in "TemperatureData" (reportAssignmentType)
1 error, 0 warnings, 0 informations

Python type checking in VSCode#

When using VSCode with the Python extension make sure that type checking is enabled.

{
    "python.analysis.typeCheckingMode": "basic"
}

Any type errors will then immediately be visible when writing code.

../../../_images/vscode_type_checks.png