Типизация 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
Другие вопросы по тегам