Generics

Generics#

Generic is a class which instances can be parameterized to work with specific types.

Syntax#

Generics have a simple sintax. You’re supposed to list the parameter types in the [] after the generic declaration.

For each generic sequence and order of types has a specific meaning, just like the regular parameters of a function.


The following cell declares a list of names with annotations.

lst: list[int]
tup: tuple[int, float, str]
dct: dict[str, int]

Here is:

  • lst: a list of integers.

  • tup: a tuple of three values with types int, float and str respectively.

  • dct: is a dictionary with str keys and int values.

I was surprised to find out that you can define the type for a generic while constructing an object. Just specify the type arguments before the constructor arguments: <ClassName>[<type arguments>](<regular arguments>)


The following code snippets will have the same meaning for linters.

val: list[int] = [1, 2, 3]
val = list[int]([1, 2, 3])

Parametrization#

Functions and classes can be defined as generic through parametrization with the type they are supposed to process. To do so, put the name of the reusable type variables in square brackets before the parentheses that define the regular parameters. The names specified in the square brackets have to be used as type and will be intepreted by linters as type specified during usage.

Note. The legacy approach to defining the generic is to use the typing.TypeVar factory (The factory is a programming approach that creates objects in a way thats other systems consider object creation to be black box).


The following cell defines a generic_function that is annotates to return the type it receives. If you passing int the linter will expect to get int as output, passing str the linter will expect to get str as output.

%%writefile /tmp/generic_parametrization.py
def generic_function[T](l: T) -> T:
    return l

int_out: int = generic_function(10)
str_out: str = generic_function("value")

var: str = generic_function(10)
Overwriting /tmp/generic_parametrization.py

Here, T is simply a reference to the type that will be determined during the function call.

The following cell runs the pyright for the script.

!pyright /tmp/generic_parametrization.py
/tmp/generic_parametrization.py
  /tmp/generic_parametrization.py:8:12 - error: Type "int" is not assignable to declared type "str"
    "int" is not assignable to "str" (reportAssignmentType)
1 error, 0 warnings, 0 informations

The linter only points only to the line that tries to assign the value returned by the generic_function(10) to a string-annotated variable.

The following cell defines the same function but by using the typing.TypeVar factory for creating a type variable.

from typing import TypeVar

T = TypeVar('T')
def generic_function(l: T) -> T:
    return l

The TypeVar function is used to create a reference to the “future” type.

Types subset#

You can define the set of types that type variable can take by:

  • typing.TypeVar("<Name>", <type_1>, <type_2>, ..., <type_n>): The result value can only be one of the defined types.

  • typing.TypeVar("<Nane>", bound=<Type>): The result type must be a subtype of the Type.


The following example shows how to define T to accept only subtypes of float and how to apply the function to int ans str objects.

%%writefile /tmp/generic_parametrization.py
from typing import TypeVar

T = TypeVar("T", bound=float)

def generic_function(l: T) -> T:
    return l

int_out: int = generic_function(10)
str_out: str = generic_function("value")
Overwriting /tmp/generic_parametrization.py

Application of the linter:

!pyright /tmp/generic_parametrization.py
/tmp/generic_parametrization.py
  /tmp/generic_parametrization.py:9:33 - error: Argument of type "Literal['value']" cannot be assigned to parameter "l" of type "T@generic_function" in function "generic_function"
    Type "Literal['value']" is not assignable to type "float"
      "Literal['value']" is not assignable to "float" (reportArgumentType)
1 error, 0 warnings, 0 informations

The output refers to the attempt to call the generic_function for string input.