使用mypy 1.2.0对移除空字段的列表排序时遇类型错误,如何解决?
问题:mypy无法识别过滤后列表的非空类型,导致sorted报错
在使用mypy 1.2.0的Python项目中,执行以下代码的lint检查:
from datetime import date, timedelta from typing import Optional from pydantic import BaseModel class ScheduleItem(BaseModel): start_date: Optional[date] = None items = [ ScheduleItem(start_date=None), ScheduleItem(start_date=date.today()), ScheduleItem(start_date=date.today() - timedelta(days=3)), ] sorted_items = sorted( [item for item in items if item.start_date], key=lambda item: item.start_date, )
得到如下错误:
error: Argument "key" to "sorted" has incompatible type "Callable[[ScheduleItem], Optional[date]]"; expected "Callable[[ScheduleItem], Union[SupportsDunderLT[Any], SupportsDunderGT[Any]]]" [arg-type] error: Incompatible return value type (got "Optional[date]", expected "Union[SupportsDunderLT[Any], SupportsDunderGT[Any]]") [return-value]
尽管传入sorted的列表已经通过过滤确保start_date不为None,但mypy无法识别这一非空状态,请问如何解决?
解决方案
方法1:使用类型断言(cast)
在lambda表达式中对start_date做非空断言,明确告知mypy此时该值不可能为None:
from typing import cast sorted_items = sorted( [item for item in items if item.start_date], key=lambda item: cast(date, item.start_date), )
方法2:给过滤后的列表添加显式类型注解
通过注解明确过滤后的列表元素类型,让mypy知晓其中的ScheduleItem的start_date非空:
from typing import List # 定义start_date非空的子类,明确类型约束 class NonNullScheduleItem(ScheduleItem): start_date: date filtered_items: List[NonNullScheduleItem] = [item for item in items if item.start_date] sorted_items = sorted(filtered_items, key=lambda item: item.start_date)
或者直接用cast标注过滤后的列表类型:
filtered_items = cast(List[ScheduleItem], [item for item in items if item.start_date]) sorted_items = sorted(filtered_items, key=lambda item: item.start_date)
方法3:自定义类型守卫(Type Guard)
编写类型守卫函数,让mypy能通过该函数识别start_date非空的ScheduleItem:
from typing import TypeGuard def has_non_null_start_date(item: ScheduleItem) -> TypeGuard[ScheduleItem]: return item.start_date is not None sorted_items = sorted( [item for item in items if has_non_null_start_date(item)], key=lambda item: item.start_date, )
方法4:升级mypy版本
mypy 1.3及后续版本优化了列表推导式的类型推断逻辑,能够自动识别过滤后的非空状态。如果项目允许,直接升级mypy即可解决问题。
内容的提问来源于stack exchange,提问作者i_trope
相关产品推荐
相关产品推荐

