mypy不识别动态键的assert校验报union-attr错误如何解决?
问题原因
mypy对字典取值的类型窄化有明确的限制:当使用字面量字符串作为键取值时,mypy可以确认前后两次访问的是同一个字典键,因此assert后的类型窄化会生效;但当使用动态变量(包括列表取元素、普通变量)作为键取值时,mypy不会默认保留窄化结果——它无法确认两次索引时使用的键值完全相同,也无法确认两次访问之间字典的对应值没有被修改,因此认为你第二次访问dict2[keys[0]]时仍然是Union[str, List[str]]类型,才会报没有append方法的错误。
解决方案
最通用且不改变运行逻辑的调整方式是:将字典对应键的值先提取为局部变量,再对局部变量做类型检查,mypy对局部变量的类型窄化是完全支持的,不会有上述限制。
修改后的_func1代码如下:
from typing import Dict, List, Union def _func1(do_something: bool) -> Dict[str, Dict[str, Union[str, List[str]]]]: dict1: Dict[str, Union[str, List[str]]] = dict() dict2: Dict[str, Union[str, List[str]]] = dict() dict3: Dict[str, Union[str, List[str]]] = dict() keys: List[str] = ['key1'] if (do_something): dict1['key1'] = 'string1' target_key = keys[0] if target_key not in dict2: dict2[target_key] = list() # 提取为局部变量后做类型检查 target_val = dict2[target_key] assert isinstance(target_val, list) target_val.append('otherstring') return {'outer_key_1': dict1, 'outer_key_2': dict2, 'outer_key_3': dict3}
其他可选方案
如果你确定该位置的类型一定是列表,不需要运行时检查,也可以使用typing.cast强制指定类型:
from typing import cast # 省略其他上下文代码 cast(List[str], dict2[keys[0]]).append('otherstring')
内容的提问来源于stack exchange,提问作者user2606240
相关产品推荐
相关产品推荐

