I am starting experiment with type annotations in Python 3 and have a problem with a function exclude_filter
, specifically annotating the items
in following code snippet (I am posting this unannotated). Briefly speaking I am trying to iterate over a list and filter out some items based on some criteria. And the type of the item in list is either instance of class or tuple of those instances in which case I am looking for criteria only in first member of the tuple.
@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))]
I've tried obviously wrong items: List[BaseItem]
with result:
Argument 1 to "exclude_filter" has incompatible type "List[Tuple[BaseItem, BaseItem]]"; expected "List[BaseItem]"
So I've tried item: List[Union[BaseItem, Tuple[BaseItem, BaseItem]]]
:
Argument 1 to "exclude_filter" has incompatible type "List[BaseItem]"; expected "List[Union[BaseItem, Tuple[BaseItem, BaseItem]]]"
Then I've tried T = TypeVar("T", BaseItem, Tuple[BaseItem, BaseItem])
and items: List[T]
a item: T
but I got:
"Tuple[BaseItem, BaseItem]" has no attribute "name"
Well I tried even more obscure combinations but nothing seems to work. What is the correct way to annotate this code?
Well I've found working but ugly solution to this problem and sadly it only works for homogenous lists.
The biggest problem with
List
being invariant is this:That is the reason I cannot use
Tuple[BaseItem, ....]
inTypeVar
and I must explicitely state all possible tuple lengths. It will be OK if I am usingSequence
but due toitems[:]
operation I can't.Also there is probably bug in mypy with conditional expression and using
isinstance()
so I need to use proper if-else block.