How to Create Custom Generic Types in Python (50/100 Days of Python)

Martin Mirakyan
2 min readFeb 20, 2023

--

Day 50 of the “100 Days of Python” blog post series covering generic types

In addition to the built-in types, the typing module in Python provides a way to define generic types, which allows you to define types that can work with values of any data type. This is useful when you want to write functions that can handle values of different types in a type-safe way.

To define a generic type, you need to use the TypeVar class defined in the typing module:

from typing import TypeVar

T = TypeVar('T')

where T is the name of the type variable, which can be any string.

Using Generic Types

You can use generic types in the same way as built-in types, by including them in your function signatures. For example, here’s a function that takes a list of values and returns the first value:

from typing import TypeVar

T = TypeVar('T')

def first(values: list[T]) -> T:
return values[0]

In this example, the generic type T is used to define the type of values in the list, so the function can work with lists of values of any type.

You can also use generic types with other type hints, such as Union:

from typing import TypeVar, Union

T = TypeVar('T')


def find(values: list[T], target: T) -> Union[T, None]:
for value in values:
if value == target:
return value
return None

Or even better:

from typing import TypeVar

T = TypeVar('T')


def find(values: list[T], target: T) -> T | None:
for value in values:
if value == target:
return value
return None

In this example, the find function takes a list of values of any type and a target value, and returns the first value in the list that matches the target, or None if no match is found.

Constraining Generic Types

In some cases, you may want to limit the types that a generic type can take. You can do this by specifying type constraints. For example, you may want to ensure that a generic type can only be used with numeric types:

from typing import TypeVar

Numeric = TypeVar('Numeric', int, float)


def average(values: list[Numeric]) -> float:
return sum(values) / len(values)

In this example, the Numeric type is defined to be a type variable that can only be either int or float. This means that the average function can only be used with lists of int or float values.

What’s next?

--

--