You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为实现去重并排序的unique函数添加正确的Python类型注解?

如何为实现去重并排序的unique函数添加正确的Python类型注解?

这个问题我之前折腾mypy的时候也碰到过,类型约束这块确实容易踩坑😅 咱们一步步来理清楚问题出在哪,再给你解决办法:

首先,你第一次尝试的问题很明确:sorted()要求元素必须支持比较操作(也就是实现__lt__这类方法),但你定义的H这个TypeVar没有任何约束,mypy无法确定传入的元素满足sorted的类型要求,所以报错了。

然后你第二次尝试自己定义抽象类的思路是对的——要同时满足可哈希(给set用)和可比较(给sorted用),但你用了名义子类型的抽象类,Python的str虽然实际实现了__lt__和__hash__,但它并没有显式继承你定义的ComparableHashable,所以mypy不认它是这个抽象类的子类,自然就报错了。

那正确的做法是用结构子类型的方式来定义约束,也就是用Python 3.8+引入的typing.Protocol(如果是更低版本可以用typing_extensions.Protocol)。Protocol的核心是:只要一个类实现了Protocol里定义的方法/属性,不管它有没有显式继承这个Protocol,mypy都会认为它符合这个类型。

具体代码如下:

from typing import Iterable, TypeVar, Protocol, Any

class HashableAndComparable(Protocol):
    def __lt__(self, other: Any) -> bool: ...
    def __hash__(self) -> int: ...

H = TypeVar("H", bound=HashableAndComparable)

def unique(x: Iterable[H]) -> list[H]:
    return sorted(list(set(x)))

# 现在测试就不会报错了
unique(a for a in ["a", "b", "c"])

为什么这个能行?因为str类虽然没继承我们的HashableAndComparable,但它实实在在实现了__lt__(字符串可以比较大小)和__hash__(字符串可以哈希),mypy通过结构检查会自动把str判定为符合这个Protocol的类型,所以不会再报错。

如果你用的是Python 3.10+,也不用特意换更简洁的写法,Protocol的方式最清晰,也最符合mypy的类型检查逻辑。另外还有个小细节:你用生成器表达式a for a in ["a", "b", "c"]传参是没问题的,直接传列表["a", "b", "c"]也一样能通过检查,因为列表也是Iterable[str]。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 06:54:32