python 3.7.0 mypy 0.641 расширяет список питонов с помощью UserList? - PullRequest
0 голосов
/ 08 ноября 2018

Я пытаюсь расширить list питонов с помощью некоторых пользовательских методов, для этого я создаю класс, унаследованный от UserList.

Я не уверен, что это правильный путь, и я хотел бычтобы получить mypy хорошо играть с UserList.

Я консультировался с cpython UserList docs и искал внутри mypy для UserList, но ничего не смог найти.

Использование:

  • mypy 0.641
  • python 3.7.0

Это минимальный пример того, что я пытаюсь достичь

from collections import UserList
from typing import List, Optional, Union


class A:
    ...


class B:
    ...


class C:
    ...


TMessage = Union[A, B, C]


class MyList(UserList):
    """Minimal example"""

    def __init__(self, data: Optional[List[TMessage]] = None) -> None:
        self.data: List[TMessage] = []
        if data:
            self.data = data[:]

    def get_last(self) -> TMessage:
        return self.data[-1]

    # other methods to be added ...


some_data = [A(), B(), C(), C(), B(), A()]
my_list_a = MyList(some_data)
my_list_b = MyList(some_data)

my_list_b = my_list_a[3:]

Mypy жалуется следующим образом

~/tmp ❯❯❯ mypy mypy_userlist.py

mypy_userlist.py:34: error: Argument 1 to "MyList" has incompatible type "List[object]"; expected "Optional[List[Union[A, B, C]]]"
mypy_userlist.py:35: error: Argument 1 to "MyList" has incompatible type "List[object]"; expected "Optional[List[Union[A, B, C]]]"
mypy_userlist.py:37: error: Incompatible types in assignment (expression has type "MutableSequence[Any]", variable has type "MyList")

Я мог бы добавить # type: ignore к конфликтующим строкам, но я бы хотел этого избежать.

Как правильно продлитьсписок python с пользовательскими методами и радует mypy?

1 Ответ

0 голосов
/ 08 ноября 2018

Я довольно новичок в MyPy, но думаю, у вас есть две проблемы. Во-первых, списки являются изменяемыми, поэтому, хотя ваш объект списка some_data удовлетворяет необходимой структуре в вашем коде, нет никаких причин, по которым объект, не относящийся к типу A, B или C, не может быть добавлен позже, то есть при компиляции, Mypy не может гарантировать, что

my_list_a = MyList(some_data) 

является действительным назначением. (посмотрите подробности в разделе общих проблем Mypy здесь )

Вы можете исправить это, явно пометив some_data:

some_data : List[TMessage] = [A(), B(), C(), C(), B(), A()]

Вторая проблема появится, когда вы исправите это, когда вы попытаетесь назначить два списка, используя нарезку. MyPy не будет знать, что вернет функция слайса, и будет жаловаться на несовместимые типы.

Чтобы исправить это, вы можете явно реализовать функциональность слайса в своем классе.

def __getitem__(self, slice_indices) -> 'MyList':
     return self.data[slice_indices]
...