Я начинаю экспериментировать с аннотациями типов в Python 3, и у меня возникла проблема с функцией exclude_filter
, в частности с аннотацией items
в следующем фрагменте кода (я публикую это без аннотации). Короче говоря, я пытаюсь перебрать список и отфильтровать некоторые элементы на основе некоторых критериев. И тип элемента в списке - это либо экземпляр класса, либо кортеж этих экземпляров, и в этом случае я ищу критерии только в первом члене кортежа.
@dataclass
class BaseItem:
name: str
something: int
def exclude_filter(items, matches):
def item_matched(item, matches):
name = item[0].name if isinstance(item, tuple) else item.name
for match in matches:
if match in name:
return True
return False
items[:] = [i for i in items if not item_matched(i, matches)]
FOOS = [BaseItem("1st foo", 10), BaseItem("2nd foo", 11)]
BARS = [BaseItem("1st bar", 20), BaseItem("2nd bar", 22)]
FOOS_AND_BARS = list(zip(FOOS, BARS))
exclude_filter(FOOS, ["1st"])
exclude_filter(BARS, ["2nd"])
exclude_filter(FOOS_AND_BARS, ["1st"])
print(FOOS)
# [BaseItem(name='2nd foo', something=11)]
print(BARS)
# [BaseItem(name='1st bar', something=20)]
print(FOOS_AND_BARS)
# [(BaseItem(name='2nd foo', something=11), BaseItem(name='2nd bar', something=22))]
Я явно ошибся items: List[BaseItem]
с результатом:
Argument 1 to "exclude_filter" has incompatible type "List[Tuple[BaseItem, BaseItem]]"; expected "List[BaseItem]"
Итак, я пробовал item: List[Union[BaseItem, Tuple[BaseItem, BaseItem]]]
:
Argument 1 to "exclude_filter" has incompatible type "List[BaseItem]"; expected "List[Union[BaseItem, Tuple[BaseItem, BaseItem]]]"
Потом попробовал T = TypeVar("T", BaseItem, Tuple[BaseItem, BaseItem])
и items: List[T]
а item: T
, но получил:
"Tuple[BaseItem, BaseItem]" has no attribute "name"
Ну, я пробовал еще более непонятные комбинации, но, похоже, ничего не работает. Как правильно аннотировать этот код?
List
наSequence
, чтобы избавиться от инвариантной проблемы (соответствуетDict
иMapping
), потому что я использую синтаксисitems[:]
в теле функции. Это просто должен быть Список. - person Tangente   schedule 23.07.2020TypeVar
и заменяю однострочное условное выражениеname = item[0].name if isinstance(item, tuple) else item.name
на обычный блок if-else, тогда оно работает. Mypy, вероятно, не может обрабатывать условные выражения с помощью isinstance (). - person Tangente   schedule 23.07.2020Union[List[BaseItem], List[Tuple[BaseItem, ...]]]
, а неList[Union[BaseItem, Tuple[BaseItem, BaseItem]]]
. Первый не не соответствует вашему описанию списка, возможно, имеющего как пустые, так и вложенные в кортежиBaseItem
s. Ваши примеры не проверяют это - желателен ли этот вариант использования? - person MisterMiyagi   schedule 23.07.2020TypeVar
действительно в порядке. Интересно, чтоList[Tuple[BaseItem, ...]]
несовместим сList[Tuple[BaseItem, BaseItem]]
из-за этой инвариантной проблемы. Он работает сSequence
, но не сList
. Более того,List[Tuple[BaseItem, ...]]
представляет собой список со всеми кортежами одинаковой длины, или каждый кортеж может иметь разную переменную длину? Я, наверное, начну обсуждение на mypy github. - person Tangente   schedule 23.07.2020