Reputation: 242
Consider the following code snippet:
class A_TUPLE(NamedTuple):
...
class Animal:
def get(self) -> Sequence[NamedTuple]:
...
def get_one(self, x: Sequence[NamedTuple]) -> None:
...
class Dog(Animal):
def get(self) -> Sequence[A_TUPLE]: # error: Return type "Sequence[A_TUPLE]" of "get" incompatible with return type "Sequence[NamedTuple]" in supertype "Animal"
...
def get_one(self, x: Sequence[A_TUPLE]) -> None: # error: Argument 1 of "get_one" is incompatible with supertype "Animal"; supertype defines the argument type as "Sequence[NamedTuple]"
...
Running mypy on the above code snippet gives error as shown in the comments.
As per mypy - invariance this should be possible.
Upvotes: 2
Views: 351
Reputation: 242
Sequence[NamedTuple]
and Sequence[A_TUPLE]
can only be compatible if the names/types of NamedTuple
is known in advance. Otherwise, with just a declaration of NamedTuple
it is not possible to validate if the return type of the derived class is compatible or type safe with the base class.
e.g. This will work:
class A_TUPLE(NamedTuple):
a: str
b: int
class Animal:
def get(self) -> Sequence[Tuple[str, int]]:
...
class Dog(Animal):
def get(self) -> Sequence[A_TUPLE]: # okay!
...
The second function def get_one(self, x: Sequence[A_TUPLE])
has a different issue.
The base class version says get_one() can take any tuple, while the derived version requires the specific type A_TUPLE. But if you have a Dog, you can treat it as an Animal. So Dog must accept everything that Animal accepts, which isn’t the case here.
Upvotes: 2