使用Python dicts进行静态类型分析

使用Python dicts进行静态类型分析,python,mypy,Python,Mypy,有人能解释为什么这段代码虽然有效,但会让mypy静态分析器以多种方式抱怨: ranges = dict() ranges['max'] = 0 ranges['services'] = [] ranges['services'].append('a') 即: 错误:赋值中的类型不兼容(表达式的类型为“List[]”,目标的类型为“int”) 错误:“int”没有属性“append” 如果我只是在ranges:dict=dict()的初始变量中添加一个类型提示,它就可以正常工作了 我不明白为什

有人能解释为什么这段代码虽然有效,但会让mypy静态分析器以多种方式抱怨:

ranges = dict()
ranges['max'] = 0
ranges['services'] = []
ranges['services'].append('a')
即:

错误:赋值中的类型不兼容(表达式的类型为“List[]”,目标的类型为“int”)
错误:“int”没有属性“append”
如果我只是在
ranges:dict=dict()的初始变量中添加一个类型提示,它就可以正常工作了


我不明白为什么静态分析器不能自己解决这个问题,特别是当我首先使用
dict
关键字初始化dict时。

字典通常用作键控集合,最重要的操作是查找与任意键相关的值。通常在字典中,每个键都有相同的类型,每个值都有相同的类型;如果值是异构的,那么表达式
ranges[key]
不一定有特定的类型(尽管可以将其表示为并集)

在代码中,静态分析器试图推断字典的类型。它期望的类型为
Dict[K,V]
形式,其中
K
V
尚未确定。第一个赋值
ranges['max']=0
给出了关于这两个未知数的信息:
K
似乎是
str
V
似乎是
int
。因此,此时,
范围
被推断为类型
Dict[str,int]

接下来的两行给出了错误,因为空列表不能用作
Dict[str,int]
中的值,并且
Dict[str,int]
中的值没有
append
方法


显式类型注释
ranges:dict=dict()
通过指定这是一个异类字典来推翻默认行为,因此值不必都具有相同的类型。给定该信息,静态分析器不会假设因为其中一个值是
int
,它们都必须是
int
s.

因为您没有提供任何注释,
mypy
必须尝试推断类型。它可以做出一些选择:

  • ranges=dict()
    表示
    range:dict[Any,Any]

    这将接受您的所有代码。它还可以接受
    范围['services'].keys()
    或任何其他操作,因为它会删除所有类型信息

  • 范围['max']=0
    意味着
    范围:Dict[str,int]

    这是
    mypy
    选择的内容。它拒绝任何非整数的键,具体到
    列表

  • ranges['services']=[]
    意味着
    range:Dict[str,list]

    这只接受您的
    范围['services']
    字段。既然
    范围['max']
    不是
    列表,那么它就无效了

  • 范围['max']=0
    范围['services']=[]
    意味着
    范围:Dict[str,Union[int,list]

    这接受值的赋值。它拒绝
    ranges['services'].append('a')
    ,因为
    ranges['services']
    可能是
    int

基本上,这些都不起作用。使用普通的
Dict[K,V]
,您的代码无法正确键入


您可以使用显式注释
范围
。由于
dict
通常不限于静态键值对,
mypy
本身不会推断出这一点

class Ranges(TypedDict):
    max: int
    services: List[str]

ranges: Ranges = dict()

很好,简洁的回答。谢谢。