我开始在 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]
aitem: T
但我得到了:
"Tuple[BaseItem, BaseItem]" has no attribute "name"
我尝试了更晦涩的组合,但似乎没有任何效果。注释此代码的正确方法是什么?
我已经找到了解决这个问题的有效但丑陋的解决方案,遗憾的是它只适用于同质列表。
BaseItemOrTuple = TypeVar(
"BaseItemOrTuple",
BaseItem,
Tuple[BaseItem, BaseItem],
Tuple[BaseItem, BaseItem, BaseItem],
Tuple[BaseItem, BaseItem, BaseItem, BaseItem],
# Et cetera for longer tuples
)
def exclude_filter(items: List[BaseItemOrTuple], matches: Sequence[str]) -> None:
def item_matched(item: BaseItemOrTuple, matches: Sequence[str]) -> bool:
if isinstance(item, tuple): # cannot use one-liner here due to possible mypy bug
name = item[0].name
else:
name = 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)]
List
不变的最大问题是:
Argument 1 to "exclude_filter" has incompatible type "List[Tuple[BaseItem, BaseItem]]"; expected "List[Tuple[BaseItem, ...]]"
这就是我不能在
Tuple[BaseItem, ....]
中使用 TypeVar
的原因,我必须明确说明所有可能的元组长度。如果我使用 Sequence
就可以了,但由于 items[:]
操作我不能。
此外,mypy 中的条件表达式和使用
isinstance()
可能存在错误,所以我需要使用正确的 if-else 块。