I recently started using type hints in my code, and have so far found them to be (mostly) very helpful.
However, one thing that I really do not like is the syntax to force the type checker to assume that a variable is of a certain type. Given this example:
import itertools
from typing import Iterable, Tuple
x: Iterable[Tuple[str, str]] = itertools.combinations('abc', 2)
# error: Incompatible types in assignment (expression has type "Iterable[Tuple[str, ...]]", variable has type "List[Tuple[str, str]]")
As far as I can tell, the recommended way to work around this is to explicitly cast
the object to force the type checker to use the specified type, e.g.:
import itertools
from typing import Iterable, Tuple, cast
x = cast(Iterable[Tuple[str, str]], itertools.combinations('abc', 2))
I personally find this solution to be a bit gross. My primary concern is that, to the inexperienced reader, it is not clear that the cast
is purely there to help the static analyzer. (If I didn't already know, I would assume based on the name and context that it is converting and doing a copy into an object of the specified type, when really there is no runtime cost.)
cast
looks like any old function call. When I see that a function is being called on a value, I expect the value to be mutated and/or some other side-effects to occur, but in this case the only side effect is that mypy
stops complaining. Type hints themselves have a distinct syntax, but I feel that this blurs the lines with a mixture of the new typing syntax and traditional python syntax. (It's already a bit blurry since you have to import
the types and can compose them, but that's another discussion.)
Is there an alternative syntax for cast
-like behavior? I haven't found anything, but I was hoping for something like:
x1 = itertools.combinations('abc', 2)) # cast: Iterable[Tuple[str, str]]
x2: Iterable[Tuple[str, str]] = itertools.combinations('abc', 2)) # type: cast
x3: Cast[Iterable[Tuple[str, str]]] = itertools.combinations('abc', 2))