在Python3中,如何键入在类实例或元组上迭代的注释函数?

2024-09-28 01:32:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我开始在Python3中尝试类型注释,但函数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"

我尝试了更模糊的组合,但似乎没有任何效果。注释此代码的正确方法是什么


Tags: nameiffoobaritemsfilteritemsomething
1条回答
网友
1楼 · 发布于 2024-09-28 01:32:30

我找到了解决这个问题的有效但丑陋的方法,不幸的是,它只适用于同质列表

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, ...]]"

这就是我不能在TypeVar中使用Tuple[BaseItem, ....]的原因,我必须明确地说明所有可能的元组长度。如果我正在使用Sequence就可以了,但是由于items[:]操作,我不能

此外,mypy中可能存在条件表达式和使用isinstance()的bug,因此我需要使用适当的if-else块

相关问题 更多 >

    热门问题