列表推导式处理鸭子类型内容时的mypy类型提示问题
问题解答
方法2为什么不报错?
方法2里你给变量d明确标注了List[Union[A, B]]类型,mypy直接复用这个类型信息,遍历d时就清楚每个元素要么是A要么是B,而这两个类都有name属性,所以不会触发报错。
方法1的类型提示为啥没用?
你在方法1里单独声明的c: Union[A, B]是个独立变量,和列表推导式里的循环变量c完全是两回事。推导式里的[A('1'), B('2')]是临时字面量,mypy默认会把这种混合不同类型的列表推断为List[object],遍历它的时候循环变量就被当成object类型,自然找不到name属性。
Python3.8下的解决方案(无需命名临时变量)
方案1:用typing.cast强制指定列表类型
直接给临时列表做类型转换,明确告诉mypy它的真实类型:
from typing import cast, List, Union, Set from dataclasses import dataclass @dataclass class A: name: str @dataclass class B: name: str f: Set[str] = {c.name for c in cast(List[Union[A, B]], [A('1'), B('2')])}
方案2:用Protocol定义公共接口
因为A和B都有name属性,可以定义一个协议来描述这个共同特性,mypy会自动识别符合协议的类型:
from dataclasses import dataclass from typing import Protocol, Set class HasName(Protocol): name: str @dataclass class A: name: str @dataclass class B: name: str f: Set[str] = {c.name for c in [A('1'), B('2')]}
这种方式更优雅,不用强制类型转换,后续其他有name属性的类也能复用这个协议。
内容的提问来源于stack exchange,提问作者mutableVoid
相关产品推荐
相关产品推荐

