Align types in type annotation Python

Viewed 45

I want the arguments of a function to be a list and a Callable that can be called upon the type of list elements, i.e.:

import typing as tp

def foo(list_: list[T], func_: tp.Callable[[T], tp.Any]):
    func_(list_[0])

I don't care what the type T is, I only care if func_ can be called upon T. Is there a way to annotate the function and not require a specific type of list elements?

1 Answers

You need to make T a TypeVar:

from typing import Callable, TypeVar

T = TypeVar("T")
U = TypeVar("U")

def foo(arr: list[T], func: Callable[[T], U]) -> None:
    func(arr[0]) 

Within a given call to foo, the arr and func arguments must have the same T:

foo(["asdf", "foo"], lambda x: x.replace("a", "b"))  # ok
foo([1, 2, 3], lambda x: x + 1)                      # ok
foo([1, 2, 3], lambda x: x.replace("foo", "bar"))    # error

I suggest using another TypeVar as a placeholder for the return value because Any can easily lead to uncaught errors in the future, whereas a TypeVar with no bound will error if you make bad assumptions about what it supports:

def foo(arr: list[T], func: Callable[[T], Any]) -> None:
    x = func(arr[0]) + 2  # ok  (danger!)
def foo(arr: list[T], func: Callable[[T], U]) -> None:
    x = func(arr[0]) + 2  # error  (good!)

If you intend for func to always be a function that returns None, just specify None instead of either U or Any.

Related