有人能解释一下为什么这段代码虽然有效,却让类型的静态分析器以多种方式抱怨:
ranges = dict()
ranges['max'] = 0
ranges['services'] = []
ranges['services'].append('a')
即:
error: Incompatible types in assignment (expression has type "List[<nothing>]", target has type "int")
error: "int" has no attribute "append"
如果我简单地向ranges: dict = dict()
的初始变量添加一个类型提示,它就会工作得很好。
我很困惑为什么静态分析器不能自己解决这个问题,特别是当我首先使用dict
关键字初始化dict的时候。
发布于 2020-02-18 12:17:31
字典通常用作键集,最重要的操作是查找与任意键关联的值。通常,在字典中,每个键都有相同的类型,每个值都有相同的类型;如果值是异构的,那么表达式ranges[key]
就不一定有特定的类型(尽管可以将它表示为一个联合)。
在您的代码中,静态分析器试图推断您的字典的类型。它所期望的类型是Dict[K, V]
形式,其中K
和V
尚未确定。第一个任务ranges['max'] = 0
给出了关于两个未知数的信息:K
似乎是str
,V
似乎是int
。因此,此时,ranges
被推断为Dict[str, int]
类型。
接下来的两行会出现错误,因为空列表不能用作Dict[str, int]
中的值,而来自Dict[str, int]
的值没有append
方法。
显式类型注释ranges: dict = dict()
通过指定这是一个异构字典来推翻默认行为,因此这些值不必都具有相同的类型。考虑到这些信息,静态分析器并不认为因为其中一个值是int
,所以它们都必须是int
的。
发布于 2020-02-18 12:35:30
由于您没有提供任何注释,mypy
必须尝试推断这些类型。它可以作出一些选择:
ranges = dict()
暗示range: Dict[Any, Any]
这将接受您所有的代码。它还将接受ranges['services'].keys()
或任何其他操作,因为它删除了所有类型信息.
ranges['max'] = 0
暗示range: Dict[str, int]
这就是mypy
选择的内容。它拒绝任何非整数的值,特别是list
.。
ranges['services'] = []
暗示range: Dict[str, list]
这只接受您的ranges['services']
字段。考虑到它不是list
.,那么ranges['max']
是无效的。
ranges['max'] = 0
和ranges['services'] = []
意味着range: Dict[str, Union[int, list]]
它接受值的赋值。它拒绝ranges['services'].append('a')
,因为ranges['services']
可能是一个ranges['services']
基本上,这些都不起作用。使用普通的Dict[K, V]
,您的代码不能很好地键入。
您可以使用typing.TypedDict
显式注释ranges
。由于dict
通常不限于静态键值对,所以mypy
不会自己推断这一点。
class Ranges(TypedDict):
max: int
services: List[str]
ranges: Ranges = dict()
https://stackoverflow.com/questions/60280254
复制相似问题