Типизация Python для подкласса списка
Я хочу иметь возможность определить, каким должно быть содержимое подкласса списка. Класс будет выглядеть следующим образом.
class A(list):
def __init__(self):
list.__init__(self)
Я хочу включить печатание так, чтобы произошло следующее.
import typing
class A(list: typing.List[str]): # Maybe something like this
def __init__(self):
list.__init__(self)
>> a = A()
>> a.append("a") # No typing error
>> a.append(1) # Typing error
2 ответа
typing
удобно предоставляет общую версию collections.MutableSequence
Итак, что-то с эффектом:
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')
Сейчас, mypy
выдает следующие ошибки:
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"
Есть некоторые хитрые аспекты набора текста __getitem__
и т.д., потому что они принимают slice
объекты тоже, но не страшные.
Обратите внимание, это полезно, потому что если вы просто попытаетесь сделать:
class HomogeneousList(collections.abc.MutableSequence, typing.Generic[T]):
....
MyPy, по крайней мере, не выдает ошибку для добавления. AFAIKT, вы должны были бы явно добавить:
def append(self, item: T) -> None:
self._data.append(item)
Какой вид удаляет много полезности collections.abc.MutableSequence
начать с. Во всяком случае, к счастью, набор предоставляет общие версии всего этого из коробки!
Обратите внимание, вы можете использовать их в общем, как я покажу, но вы также можете сделать что-то вроде:
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
До Python 3.9 вы можете использовать:
import typing
class A(typing.List[str]):
pass
Это указывает вашей программе проверки типов, что элементы класса
A
должен быть типа
str
. Во время выполнения это ведет себя так же, как создание подкласса
list
. PEP 484 определяет, как ведет себя система ввода. В частности, пример в этом разделе PEP делает что-то похожее на то, что вы спрашиваете, но с
typing.Dict
вместо
typing.List
.
В Python 3.9+ вы можете использовать встроенный тип вместо импорта из type . Класс становится:
class A(list[str]):
pass