如何为含Optional[int]的列表正确注解类型以通过mypy检查
问题:为包含None的列表正确添加类型注解以通过mypy检查
初始代码与报错
最初编写的代码如下:
from typing import List, Optional my_list: List[Optional[int]] = list() for i in range(7): my_list.append(i) my_list = sorted(my_list) if (len(my_list) > 0): my_list.append(None) # do something with my_list
执行mypy x.py后触发类型检查错误:
x.py:6: error: Value of type variable "SupportsRichComparisonT" of "sorted" cannot be "Optional[int]"
原因是Optional[int]包含None类型,而None无法与整数进行大小比较,不符合sorted对可比较元素的要求。
修改后的代码与新报错
将列表类型改为List[int]后:
from typing import List my_list: List[int] = list() for i in range(7): my_list.append(i) my_list = sorted(my_list) if (len(my_list) > 0): my_list.append(None) # do something with my_list
再次执行mypy x.py又出现新错误:
x.py:8: error: Argument 1 to "append" of "list" has incompatible type "None"; expected "int"
此时列表被标注为仅允许整数元素,无法添加None。
生产环境代码
实际生产中的业务代码如下:
from typing import List, Optional def parse_job_attributes(string: str, tokens: List[str]) -> List[str]: indices = [] for token in tokens: if token in string.lower(): indices.append(string.lower().index(token)) sorted_indices: List[Optional[int]] = list(sorted(indices)) # indices = sorted(indices) if len(sorted_indices) > 0: sorted_indices.append(None) parts = [string[sorted_indices[i]:sorted_indices[i + 1]] for i in range(len(sorted_indices) - 1)] return parts
解决方案
方法1:拆分列表处理阶段,先排序纯整数列表再转换类型
先维护一个纯整数列表完成排序操作,再将其转换为允许None的列表类型,最后添加None元素:
from typing import List, Optional my_list: List[int] = list() for i in range(7): my_list.append(i) # 对纯整数列表排序,无类型检查问题 sorted_int_list = sorted(my_list) # 转换为允许包含None的列表类型 my_list_with_none: List[Optional[int]] = sorted_int_list if len(my_list_with_none) > 0: my_list_with_none.append(None) # do something with my_list_with_none
对应生产代码的修改:
from typing import List, Optional def parse_job_attributes(string: str, tokens: List[str]) -> List[str]: indices = [] for token in tokens: if token in string.lower(): indices.append(string.lower().index(token)) # 先排序纯整数列表 sorted_indices_int: List[int] = sorted(indices) # 转换为允许包含None的类型 sorted_indices: List[Optional[int]] = sorted_indices_int if len(sorted_indices) > 0: sorted_indices.append(None) parts = [string[sorted_indices[i]:sorted_indices[i + 1]] for i in range(len(sorted_indices) - 1)] return parts
方法2:使用类型断言跳过检查
如果能确定排序阶段的列表实际没有None元素,可以用cast告诉mypy排序后的列表类型:
from typing import List, Optional, cast my_list: List[Optional[int]] = list() for i in range(7): my_list.append(i) # 断言排序后的列表仍为List[Optional[int]](因原列表此时无None) my_list = cast(List[Optional[int]], sorted(my_list)) if len(my_list) > 0: my_list.append(None) # do something with my_list
生产代码中对应修改:
from typing import List, Optional, cast def parse_job_attributes(string: str, tokens: List[str]) -> List[str]: indices = [] for token in tokens: if token in string.lower(): indices.append(string.lower().index(token)) sorted_indices: List[Optional[int]] = cast(List[Optional[int]], sorted(indices)) if len(sorted_indices) > 0: sorted_indices.append(None) parts = [string[sorted_indices[i]:sorted_indices[i + 1]] for i in range(len(sorted_indices) - 1)] return parts
核心逻辑说明
问题的本质是sorted要求元素必须支持大小比较,而None无法与整数比较,因此不能直接对List[Optional[int]]排序。解决思路要么先处理纯整数列表的排序,再转换为允许None的类型,要么用类型断言明确告知mypy当前列表的实际元素类型。
内容的提问来源于stack exchange,提问作者user2606240
相关产品推荐
相关产品推荐

