Is it possible to use type hinting when unpacking a tuple? I want to do this, but it results in a SyntaxError:
from typing import Tuple
t: Tuple[int, int] = (1, 2)
a: int, b: int = t
# ^ SyntaxError: invalid syntax
According to PEP-0526, you should annotate the types first, then do the unpacking
a: int
b: int
a, b = t
In my case i use the typing.cast function to type hint an unpack operation.
t: tuple[int, int] = (1, 2)
a, b = t
# type hint of a -> Literal[1]
# type hint of b -> Literal[2]
By using the cast(new_type, old_type) you can cast those ugly literals into integers.
from typing import cast
a, b = cast(tuple[int, int], t)
# type hint of a -> int
# type hint of b -> int
This can be useful while working with Numpy NDArrays with Unknown types
# type hint of arr -> ndarray[Unknown, Unknown]
a, b = cast(tuple[float, float], arr[i, j, :2]
# type hint of a -> float
# type hint of b -> float
Related
The following code gives error for tuple constructor:
def foo() -> tuple[int, int, bool]:
a: int = 1
b: int = 2
c: bool = True
results: tuple[int, int, bool] = tuple((a, b, c)) # mypy fails
results: tuple[int, int, bool] = (a, b, c) # mypy success
results: tuple[int, int, bool] = a, b, c # mypy success
return results
Error as below:
error: Incompatible types in assignment (expression has type "Tuple[object, ...]", variable has type "Tuple[int, int, bool]") [assignment]
edited:
error: Incompatible types in assignment (expression has type "Tuple[int, ...]", variable has type "Tuple[int, int, bool]")
Note, I get a slightly different error:
x.py:6: error: Incompatible types in assignment (expression has type "Tuple[int, ...]", variable has type "Tuple[int, int, bool]") [assignment]
Found 1 error in 1 file (checked 1 source file)
With:
mbp16-2019:~ jarrivillaga$ mypy --version
mypy 0.990 (compiled: yes)
So, you can think of tuple being type-hinted like this (see that actual typeshed hints here:
import typing
T = typing.TypeVar("T")
class tuple(object):
def __new__(cls, data: typing.Iterable[T]) -> tuple[T, ...]:
...
So the type of the literal:
data: tuple[int, int, bool] = (a, b, c)
gets promoted to:
data: tuple[int, ...]
Note, that bool is a subclass of int.
I suspect this is what is happening with your real example, (maybe you aren't using bool but something like str, in which case it has to promote to object).
I have two variables a and b that are either int or str.
I write an assertion that insists a and b are either both ints or strs.
If I typenarrow a to an int, is there a way for mypy to infer b is also an int?
Here is some sample code.
Mypy version:
mypy 0.980+dev.0f17aff06ac1c05c442ba989e23655a2c6adbfbf (compiled: no)
Thanks for your help.
def my_func(a: int | str, b: int | str):
# We assert one of the statements is true: 1) a and b are ints, or 2) a and b are strings.
# In the case of an int a, and a string b, or vice versa, this assertion will fail.
assert isinstance(a, int) == isinstance(b, int)
# Another alternative assertion
assert type(a) == type(b)
if isinstance(a, int):
reveal_type(b) # mypy still thinks b is int or str
Using typing.TypeVar:
from typing import TypeVar
T = TypeVar('T', int, str)
def reveal_type(a: int):
pass
def foo(a: str):
pass
def my_func(a: T, b: T):
if isinstance(a, int):
reveal_type(b) # pass
else:
foo(b) # pass
If we simply exchange the calling positions of the two functions, mypy will find that they are all wrong calls and give two errors:
def my_func(a: T, b: T):
if isinstance(a, int):
foo(b) # Argument 1 to "foo" has incompatible type "int"; expected "str" (16:12)
else:
reveal_type(b) # Argument 1 to "reveal_type" has incompatible type "str"; expected "int" (18:20)
My code is as follows:
from typing import Tuple
a: Tuple[int, int] = tuple(sorted([1, 3]))
Mypy tells me:
Incompatible types in assignment (expression has type "Tuple[int,
...]", variable has type "Tuple[int, int]")
What am I doing wrong? Why can't Mypy figure out that the sorted tuple will give back exactly two integers?
The call to sorted produces a List[int] which carries no information about length. As such, producing a tuple from it also has no information about the length. The number of elements simply is undefined by the types you use.
You must tell your type checker to trust you in such cases. Use # type: ignore or cast to unconditionally accept the target type as valid:
# ignore mismatch by annotation
a: Tuple[int, int] = tuple(sorted([1, 3])) # type: ignore
# ignore mismatch by cast
a = cast(Tuple[int, int], tuple(sorted([1, 3])))
Alternatively, create a length-aware sort:
def sort_pair(a: T, b: T) -> Tuple[T, T]:
return (a, b) if a <= b else (b, a)
Is it possible to use type hinting when unpacking a tuple? I want to do this, but it results in a SyntaxError:
from typing import Tuple
t: Tuple[int, int] = (1, 2)
a: int, b: int = t
# ^ SyntaxError: invalid syntax
According to PEP-0526, you should annotate the types first, then do the unpacking
a: int
b: int
a, b = t
In my case i use the typing.cast function to type hint an unpack operation.
t: tuple[int, int] = (1, 2)
a, b = t
# type hint of a -> Literal[1]
# type hint of b -> Literal[2]
By using the cast(new_type, old_type) you can cast those ugly literals into integers.
from typing import cast
a, b = cast(tuple[int, int], t)
# type hint of a -> int
# type hint of b -> int
This can be useful while working with Numpy NDArrays with Unknown types
# type hint of arr -> ndarray[Unknown, Unknown]
a, b = cast(tuple[float, float], arr[i, j, :2]
# type hint of a -> float
# type hint of b -> float
This isn't my exact use case, but it's similar. Suppose I want to define two typing annotations:
Matrix = np.ndarray
Vector = np.ndarray
Now, I want a potential type-checker to complain when I pass a Matrix to a function that accepts a Vector:
def f(x: Vector):
...
m: Matrix = ...
f(m) # Bad!
How do I mark these types as incompatible?
It appears that I can use typing.NewType to create distinct types:
from typing import NewType
A = NewType('A', int)
B = NewType('B', int)
def f(a: A):
pass
b: B
f(b)
gives
a.py:11: error: Argument 1 to "f" has incompatible type "B"; expected "A"
Unfortunately, it doesn't work with np.ndarray until either numpy implements type hinting or NewType supports a base type of Any.