实例化时是否设置了 Python 3.x 字典 lint 类型检查(键入)

Is Python 3.x dictionary lint type check (typing) set at instantiation

我有一个配置字典,我在 dunder init 调用的层次结构中加载值,每个调用实例化部分配置。尝试为此添加输入时我收到了一个奇怪的行为(或者我做错了什么)。我得到的行为与字典给出的类型一致,这些类型只在它的第一个声明中插入它,更新扩展和添加键似乎并没有改变字典在访问它时尽可能声明的类型,这是一个简单的我写的代码来说明问题:

import re


def foo(a: int = 1, b: str = "b"):
    d = {"a": a}
    d.update({"b": b})
    print(re.findall(d["b"], "baba"))


foo()

代码当然有效并输出 ['b', 'b'](没有双关语意)但我的 pycharm 给出了两个警告:

  1. 在更新线上:Unexpected type(s):<br>(Dict[str, str])<br>Possible types:<br>(Mapping[str, int])<br>(Iterable[Tuple[str, int]])
  2. 在查找器行上:Expected type 'Union[bytes, str, __Regex]', got 'int' instead

我的问题是,我对这个原因的分析是否正确(dict 在实例化时设置其类型)?是否有 pythonic 方法来修复这些警告?

updating extending and adding keys does not seem to change the types a dictionary declares

这是设计使然。如果你有一些变量声明为 Dict[str, int] 类型,你可能希望 mypy 在你不小心尝试 运行 代码如 var['foo'] = 'bar'.

时大声抱怨

在这种情况下,由于您将 d 分配给了字符串字典到整数,mypy 假设您的意思是该类型只是 Dict[str, int].

如果您希望对代码进行类型检查,您有多种选择:

  1. 明确声明您期望字典的值是什么类型,并使用断言或强制转换来确认某些键的类型是您期望的类型:

    def foo(a: int = 1, b: str = "b") -> None:
        d: Dict[str, Union[int, str]] = {"a": a}
        d.update({"b": b})
    
        # If you want to check your assumption at runtime
        b_regex = d["b"]
        assert isinstance(b_regex, str)
        print(re.findall(b_regex, "baba"))
    
        # If you don't want/don't need to check the type
        print(re.findall(cast(str, d["b"]), "baba"))
    
  2. 放弃静态输入字典,将值设置为 the dynamic 'Any':

    def foo(a: int = 1, b: str = "b") -> None:
        d: Dict[str, Any] = {"a": a}
        d.update({"b": b})
        print(re.findall(d["b"], "baba"))
    
  3. 使用TypedDict mypy extension表示dict将只包含某些字符串键,其中每个键都有一些特定类型的对应值。

    请注意,这目前是一个仅限 mypy 的扩展,尽管有计划在不久的将来将其作为成熟的类型添加到 PEP 484 中。一旦发生这种情况,PyCharm 实际上有义务理解 TypedDict(尽管他们可能已经提前添加了支持,不确定)。