Issue
I slightly modified the documented mypy generic example but got an error:
from typing import Generic, TypeVar, Union
T = TypeVar("T", bound=Union[int, float])
class Person(Generic[T]):
def __init__(self, salary: T) -> None:
self.salary: T = salary
def get_yearly_bonus(self, amount: T) -> None:
self.salary += amount
def __str__(self) -> str:
return f"Person(salary={self.salary})"
p = Person[int](9)
p.get_yearly_bonus(6)
print(p)
It seems mypy fails to recognize the fact that self.salary
and amount
must
be of the same type.
$ mypy test.py
test.py:11: error: Incompatible types in assignment (expression has type "float", variable has type "T")
test.py:11: error: Unsupported operand types for + (likely involving Union)
Found 2 errors in 1 file (checked 1 source file)
Solution
The problem isn't mypy failing to recognize that self.salary
and amount
share a type. mypy knows they both have type T
, whatever T
is.
The problem is that T
isn't guaranteed to be either int
or float
. T
can be any subtype of Union[int, float]
. It could be int
, or float
, or any subclass of those classes, like bool
, or it could even be Union[int, float]
!
For a sum of two objects of type T
, mypy cannot assume the sum has type T
. The most specific type mypy can deduce for the sum (accounting for mypy's weird special case that treats int
as a subtype of float
) is float
, which isn't assignable to self.salary
.
If you wanted T
to be either int
or float
, a union bound isn't the way to do that. The syntax for "either int
or float
" is
T = TypeVar('T', int, float)
With T
specified this way, mypy can type-check Person
against both possible types and see that the class is valid both ways.
Answered By - user2357112
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.