Revisamos de forma cada artículo en nuestro espacio con el objetivo de mostrarte en todo momento información con la mayor veracidad y actualizada.
Solución:
typing
convenientemente proporciona una versión genérica de collections.MutableSequence
, así que algo en el sentido de:
import typing
T = typing.TypeVar('T')
class HomogeneousList(typing.MutableSequence[T]):
def __init__(self, iterable: typing.Iterable[T]=()) -> None:
self._data: typing.List[T] = []
self._data.extend(iterable)
@typing.overload
def __getitem__(self, index: int) -> T: ...
@typing.overload
def __getitem__(self, index: slice) -> HomogeneousList[T]: ...
def __getitem__(self, index):
return self._data[index]
@typing.overload
def __setitem__(self, index: int, item: T) -> None: ...
@typing.overload
def __setitem__(self, index: slice, item: typing.Iterable[T]) -> None: ...
def __setitem__(self, index, item):
self._data[index] = item
def __delitem__(self, index: typing.Union[int, slice]) -> None:
del self._data[index]
def __len__(self) -> int:
return len(self._data)
def insert(self, index: int, item: T) -> None:
self._data.insert(index, item)
string_list = HomogeneousList[str]()
string_list.append('foo')
string_list.append(42)
int_list = HomogeneousList[int]()
int_list.append(42)
int_list.append('foo')
Ahora, mypy
da los siguientes errores:
test.py:36: error: Argument 1 to "append" of "MutableSequence" has incompatible type "int"; expected "str"
test.py:41: error: Argument 1 to "append" of "MutableSequence" has incompatible type "str"; expected "int"
Hay algunos aspectos complicados de escribir __getitem__
etc porque aceptan slice
objetos también, pero no terribles.
Tenga en cuenta que esto es útil, porque si solo intenta hacer:
class HomogeneousList(collections.abc.MutableSequence, typing.Generic[T]):
....
MyPy, al menos, no arroja un error para agregar. AFAIKT, tendrías que agregar explícitamente: ‘
def append(self, item: T) -> None:
self._data.append(item)
Lo que elimina gran parte de la utilidad de collections.abc.MutableSequence
para empezar. De todos modos, afortunadamente, ¡escribir proporciona versiones genéricas de todos estos listos para usar!
Tenga en cuenta que puede usarlos de forma genérica, como he mostrado, pero también puede hacer algo como:
class StringList(HomogeneousList[str]):
pass
mylist = StringList([1,2,3]) # mypy error
mylist = StringList('abc') # no error
mylist.append('foo') # no error
mylist.append(42) # mypy error
Antes de Python 3.9, puede usar:
import typing
class A(typing.List[str]):
pass
Esto le indica a su verificador de tipos que los elementos de la clase A
debe ser de tipo str
. En tiempo de ejecución, esto se comporta igual que crear una subclase de list
. PEP 484 especifica cómo se comporta el sistema de tipeo. En particular, el ejemplo en esta sección del PEP hace algo similar a lo que estás preguntando, pero con typing.Dict
en vez de typing.List
.
En Python 3.9+, puede usar el tipo incorporado en lugar de importar desde la escritura. La clase se convierte en:
class A(list[str]):
pass
Si te sientes impulsado, puedes dejar una noticia acerca de qué le añadirías a este post.