Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use python's typing library to specify more than one possible type

I want to specify a type hint for a function can receive either a list of strs or a list of ints. Is there a way to do this using Python? Something like:

from typing import List

def my_function(list_arg: List[str|int]):

    ...
    ...
like image 898
vahndi Avatar asked Oct 30 '22 04:10

vahndi


1 Answers

Union is intended precisely for this situation. It creates a new type that can be any of the types you specify:

from typing import Union, List
def my_function(list_arg: Union[List[str], List[int]]) -> None: ...

If you use it often, make a type alias:

MyList = Union[List[str], List[int]]
def my_function(list_arg: MyList) -> None: ...

I wouldn't recommend using a generic function as @user6269244 answer suggests unless you need it for some specific reason. Although T = TypeVar('T', int, str) will work in a simple case, it will be more restrictive.

For example, suppose you have something like this:

def apply_my_function(list_of_lists: List[MyList]) -> None:
  # each item in list_of_lists is either a List[int] or List[str]
  for arg in list_of_lists:
    my_function(arg)

In this code, you have no chioce: you need a Union (List[List[T]] won't let you store both a list of int and a list of str because T can't switch between str and int in the same expression).

But since you use Union in the code that calls my_function, you'll also have to use Union in the signature of my_function itself.

In addition, generics increase the complexity of the types, and at some point you will run into the limitations of the type system. So it's better to reserve generics for cases where you really need them, for example if you want the return type of my_function to depend on the argument type:

T = TypeVar("T", int, str)

# this can't be achieved with Union:
def my_function(list_arg: List[T]) -> T: ...
like image 91
max Avatar answered Nov 15 '22 06:11

max