The following code:
from typing import Union
def process(actions: Union[list[str], list[int]]) -> None:
for pos, action in enumerate(actions):
act(action)
def act(action: Union[str, int]) -> None:
print(action)
generates a mypy error: Argument 1 to "act" has incompatible type "object"; expected "Union[str, int]"
However when removing the enumerate function the typing is fine:
from typing import Union
def process(actions: Union[list[str], list[int]]) -> None:
for action in actions:
act(action)
def act(action: Union[str, int]) -> None:
print(action)
Does anyone know what the enumerate function is doing to effect the types? This is python 3.9 and mypy 0.921
CodePudding user response:
enumerate.__next__ needs more context than is available to have a return type more specific than Tuple[int, Any], so I believe mypy itself would need to be modified to make the inference that enumerate(actions) produces Tuple[int,Union[str,int]] values.
Until that happens, you can explicitly cast the value of action before passing it to act.
from typing import Union, cast
StrOrInt = Union[str, int]
def process(actions: Union[list[str], list[int]]) -> None:
for pos, action in enumerate(actions):
act(cast(StrOrInt, action))
def act(action: Union[str, int]) -> None:
print(action)
You can also make process generic (which now that I've thought of it, is probably a better idea, as it avoids the overhead of calling cast at runtime).
from typing import Union, cast, Iterable, TypeVar
T = TypeVar("T", str, int)
def process(actions: Iterable[T]) -> None:
for pos, action in enumerate(actions):
act(action)
def act(action: T) -> None:
print(action)
Here, T is not a union of types, but a single concrete type whose identity is fixed by the call to process. Iterable[T] is either Iterable[str] or Iterable[int], depending on which type you pass to process. That fixes T for the rest of the call to process, which every call to act must take the same type of argument.
CodePudding user response:
I don't know how it's affecting the types. I do know that using len() can work the same way. It is slower but if it solves the problem it might be worth it. Sorry that it's not much help
CodePudding user response:
Seems like mypy isn't able to infer the type and generalizes to object. Might be worth opening an issue at their side. As a workaround you could annotate 'action'. This would remove the error. Does it work if you import the (legacy) List from typing?
