如何在python中定义这行代码以便通过mypy检查

use*_*231 1 python python-3.x mypy python-typing

我的 python 代码中有这样的定义:

options = defaultdict(lambda: defaultdict(lambda: defaultdict(str)))
options['modem1']['ByCost'] = ...
options['modem1']['ByCarrier'] = ...
options['modem1']['BySimSignal'] = ...
options['modem1']['SwitchBackByTimer'] = ...
Run Code Online (Sandbox Code Playgroud)

在我的预提交/mypy 检查期间它失败了,因为消息如下:

Need type annotation for 'options'
Run Code Online (Sandbox Code Playgroud)

由于我没有看到这段代码有任何问题,那么有什么解决办法可以让它通过 mypy 检查这一行吗?

顺便说一句,除了在我的代码中设置之外,我正在寻找其他方法:

disable_error_codes with error code var-annotated
Run Code Online (Sandbox Code Playgroud)

多谢 !

杰克

Sha*_*ger 5

在 Python 3.9+ 上,多亏了 PEP 585,您可以使用defaultdict自身进行类型注释,从而使这个过程变得简单,尽管有些冗余/冗长(请参阅答案底部的 3.9+-only 解决方案,该解决方案稍微不那么冗余/冗长,但不能可以轻松向后移植到 3.8 及更早版本):

from collections import defaultdict

options: defaultdict[str, defaultdict[str, defaultdict[str, str]]] = defaultdict(lambda: defaultdict(lambda: defaultdict(str)))
Run Code Online (Sandbox Code Playgroud)

请注意,这假设您实际上拥有三级defaultdict;您的代码仅下降两级,因此如果您这样做,您将收到检查错误:

options['modem1']['ByCost'] = 'abc'
Run Code Online (Sandbox Code Playgroud)

因为你确实需要多一级的str密钥:

options['modem1']['ByCost']['xyz'] = 'abc'
Run Code Online (Sandbox Code Playgroud)

如果您实际上想要两层defaultdict,请将其修剪回:

options: defaultdict[str, defaultdict[str,str]] = defaultdict(lambda: defaultdict(str))

options['modem1']['ByCost'] = 'abc'
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Python 3.8或更早版本,请将注释替换defaultdicttyping.DefaultDict注释,使其:

from collections import defaultdict
from typing import DefaultDict

options: DefaultDict[str, DefaultDict[str, DefaultDict[str, str]]] = defaultdict(lambda: defaultdict(lambda: defaultdict(str)))
# Or if only two levels:
options: DefaultDict[str, DefaultDict[str, str]] = defaultdict(lambda: defaultdict(str))
Run Code Online (Sandbox Code Playgroud)

减少冗余的解决方案

注意:3.9 的用法允许您注释使用注释类型,因此作为仅限 3.9+ 的解决方案,您可以这样做(为了简单起见,显示两层情况):

options = defaultdict[str, defaultdict[str,str]](lambda: defaultdict(str))
Run Code Online (Sandbox Code Playgroud)

并且不需要在options其自身上显式提供注释,因为顶层defaultdict已经被注释,隐式注释了它分配给的变量。