'Should mypy infer type from Union options?
In the following code fn_int
will only be called with an int
as an argument, yet mypy
complains I might be passing it a str
(viceversa for fn_str
).
Is there something I'm missing here?
Should/can I somehow narrow down the type before passing arguments to fn_int
and fn_str
?
from typing import Union
def fn_int(arg: int) -> None:
print(arg)
def fn_str(arg: str) -> None:
print(arg)
def fn(arg: Union[str, int]) -> None:
if arg in range(4):
fn_int(arg)
elif arg == "str":
fn_str(arg)
else:
raise ValueError
> mypy mypy_test.py
mypy_test.py:15: error: Argument 1 to "fn_int" has incompatible type "Union[str, int]"; expected "int" [arg-type]
mypy_test.py:17: error: Argument 1 to "fn_str" has incompatible type "Union[str, int]"; expected "str" [arg-type]
Solution 1:[1]
What you're looking for is called type narrowing, and mypy doesn't do type narrowing for ==
or in
comparisons. After all, they don't really guarantee type. As a fairly common example, after x == 3
or x in range(5)
, x could still be a float rather than an int. (Sure, a standard string won't pass an in range(4)
check, and a standard int won't pass an == "str"
check, but you could have a weird subclass.)
mypy will do type narrowing for the following kinds of expressions:
isinstance(x, SomeClass)
narrowsx
toSomeClass
.issubclass(x, SomeClass)
narrowsx
toType[SomeClass]
.type(x) is SomeClass
narrowsx
toSomeClass
.callable(x)
narrowsx
to callable type.
You can also write your own type guards with typing.TypeGuard
, and mypy will understand those too.
Solution 2:[2]
arg is str or int, but you never check which type it is,
therefore check with if isinstance(arg, int)
.
then mypy knows that this function is only called if it is of desired type.
Example:
if isinstance(arg, int):
fn_int(arg)
elif isinstance(arg, str):
fn_str(arg)
else:
raise ValueError
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | user2357112 |
Solution 2 | Av3g3n |