Tengo una subclase de list que agrega algunas cosas administrativas a los componentes de la lista. Todo funciona bien, pero mypy se queja de la firma de la super llamada a __setitem__ . Aquí está el problema reducido a su mínima expresión:
from typing import List, Iterable, Union, overload from typing_extensions import SupportsIndex class MyData: pass class MyDataSeq(List[MyData]): @overload def __setitem__(self, index: SupportsIndex, value: MyData) -> None: ... @overload def __setitem__(self, index: slice, value: Iterable[MyData]) -> None: ... def __setitem__(self, index: Union[SupportsIndex, slice], value: Union[MyData, Iterable[MyData]]) -> None: # Administrative stuff deleted super().__setitem__(index, value) def __delitem__(self, index: Union[SupportsIndex, slice]) -> None: # Administrative stuff deleted super().__delitem__(index) Cuando ejecuto mypy en esto, obtengo:
src\seq.py:18: error: Invalid index type "Union[SupportsIndex, slice]" for "MyDataSeq"; expected type "SupportsIndex" src\seq.py:18: error: Incompatible types in assignment (expression has type "Union[MyData, Iterable[MyData]]", target has type "MyData") Found 2 errors in 1 file (checked 1 source file) Estoy perdido aquí, porque obviamente __setitem__ , al igual que __delitem__ , acepta tanto un int -like ( SupportsIndex ) como un objeto de slice como su primer argumento. Es casi como si mypy alguna manera llegara a la conclusión de que solo se admiten objetos tipo int , lo que coincide con el segundo error de que espera solo un MyData como segundo argumento, no Iterable[MyData] .
Probé esto en Python 3.7 y 3.9, los errores son los mismos. Por supuesto, puedo decirle a mypy que ignore estos errores, pero realmente me gustaría saber cuál es la causa y cómo resolverlo. ¿Algunas ideas?
De acuerdo con este problema similar. Mypy no usa información de sobrecarga para verificar el tipo del cuerpo de la función.
Para resolver su problema, podría darle una pista a Mypy de qué tipos le está pasando por medio de isinstance . Al igual que:
from typing import List, Iterable, Union, overload from typing_extensions import SupportsIndex class MyData: pass class MyDataSeq(List[MyData]): @overload def __setitem__(self, index: SupportsIndex, value: MyData) -> None: ... @overload def __setitem__(self, index: slice, value: Iterable[MyData]) -> None: ... def __setitem__(self, index: Union[SupportsIndex, slice], value: Union[MyData, Iterable[MyData]]) -> None: # Administrative stuff deleted if isinstance(index, slice) and isinstance(value, Iterable): super().__setitem__(index, value) elif isinstance(index, int) and isinstance(value, MyData): super().__setitem__(index, value) else: raise TypeError(f"{index}/{value} Invalid index/value type.") def __delitem__(self, index: Union[SupportsIndex, slice]) -> None: # Administrative stuff deleted super().__delitem__(index)No necesita anotar la implementación, solo las definiciones decoradas.
class MyDataSeq(List[MyData]): @overload def __setitem__(self, index: SupportsIndex, value: MyData) -> None: ... @overload def __setitem__(self, index: slice, value: Iterable[MyData]) -> None: ... def __setitem__(self, index, value): # Administrative stuff deleted super().__setitem__(index, value) def __delitem__(self, index: Union[SupportsIndex, slice]) -> None: # Administrative stuff deleted super().__delitem__(index) (Esto dejará un problema similar para que se resuelva __delitem__ , pero creo que eso es un asunto para una pregunta separada).