If I have
def get(
ids: str | list[str] | int | list[int],
) -> float | list[float]:
Is there a way to specify in return value annotation that a list of float
s is output only when the input ids
is a list of str
s or int
s?
2
One way to do this is by using the @overload
decorator to create 2 extra function signatures, one for int | str
that returns float
and one for list[str] | list[int]
that returns list[float]
and then have the actual function definition like you have now.
from typing import overload
@overload
def test(
ids:str | int,
) -> float:...
@overload
def test(
ids:list[str] | list[int],
) -> list[float]:...
def test(
ids: str | list[str] | int | list[int],
) -> float | list[float]:...
0
Your get
is really two different functions. One converts its argument to a float
; the other uses the first to convert a list of arguments to a list of float
s.
def get(x: str | int) -> float:
...
def gets(xs: list[str] | list[int]) -> list[float]:
return [get(xs) for x in xs]
You only feel compelled to combine them into a single function (for “convenience”) because Python lacks a built-in function that makes gets
easy to create on the fly from get
.
def listmap[A, B](f: Callable[[A], B]) -> Callable[[list[A]], listB]:
return lambda xs: [f(x) for x in xs]
floats = listmap(get)([1, "2", 3])
This is an example of “inversion of control”: instead of making get
decide what to do based on the type of its argument, you decide which function to call based on the type of the argument.