from typing_extensions import Literal
# from typing import Literal # Python 3.8 or higher
def fun(b: int) -> Literal["a", "b", "c"]:
if b == 0:
return "a"
if b == 1:
return "b"
return "d"
mypy is able to detect the return "d"
as a invalid statement:
error: Incompatible return value type (got "Literal['d']",
expected "Union[Literal['a'], Literal['b'], Literal['c']]")
Python 3.8
Thanks to the PEP 586, the Literal
is already included by default in the Python 3.8 typing
module.
TLDR: You need a TypeVar
for the return type of calling t
:
def fun(t: Callable[[int], R]) -> R:
...
Constraining on a type is too restrictive here. The function accepts any Callable
that takes an integer, and the return type of the function is that of the Callable
. This can be specified using a TypeVar
for the return type:
from typing import Callable, TypeVar
R = TypeVar('R') # the variable return type
def fun(t: Callable[[int], R]) -> R:
return t(42)
fun(int) # Revealed type is 'builtins.int*'
fun(float) # Revealed type is 'builtins.float*'
reveal_type(fun(lambda x: str(x))) # Revealed type is 'builtins.str*'
This works for types as well, because type instantiation is a call.
If a more complex signature, e.g. with keyword arguments, is needed, use Protocol
(from typing
or typing_extensions
).
Note that if one explicitly wants to pass only 42
to the Callable
, Literal
(from typing
or typing_extensions
) can be used to specify that.
R = TypeVar('R')
def fun(t: Callable[[Literal[42]], R]) -> R:
return t(42)
Note that any function of the type Callable[[int], R]
also satisfies Callable[[Literal[42]], R]
.
Best Answer
EDIT: Since Python 3.9 and the acceptance of PEP 585, you should use the built-in
tuple
class to typehint tuples.You can use a
typing.Tuple
type hint (to specify the type of the content of the tuple, if it is not necessary, the built-in classtuple
can be used instead):