如何键入注释字典理解?

l0b*_*0b0 1 python mypy python-typing

Mypy 认为这对以下情况有效strict = true

from typing import Dict, TypeVar

KeyType = TypeVar("KeyType")
ValueType = TypeVar("ValueType")


class InvertibleDict(Dict[KeyType, ValueType]):
    def __inverse__(self) -> "InvertibleDict[ValueType, KeyType]":
        new_instance: "InvertibleDict[ValueType, KeyType]" = self.__class__()
        for key, value in self.items():
            new_instance[value] = key
        return new_instance
Run Code Online (Sandbox Code Playgroud)

但是,它不接受相同代码的以下更简洁版本,在最后一行说“关键字必须是字符串”:

from typing import Dict, TypeVar

KeyType = TypeVar("KeyType")
ValueType = TypeVar("ValueType")


class InvertibleDict(Dict[KeyType, ValueType]):
    def __inverse__(self) -> "InvertibleDict[ValueType, KeyType]":
        return self.__class__(**{value: key for key, value in self.items()})
Run Code Online (Sandbox Code Playgroud)

jua*_*aga 5

MyPy 在这里是正确的,它在您的实现中捕获了一个错误(静态类型检查的美妙之处)。类型:

{value: key for key, value in self.items()}
Run Code Online (Sandbox Code Playgroud)

Dict[KeyType, ValueType],但是当您这样做时,通常会失败:

dict(**some_mapping)
Run Code Online (Sandbox Code Playgroud)

不保证是字符串的地方

观察:

>>> dict(**{1:2,3:4})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keywords must be strings
Run Code Online (Sandbox Code Playgroud)

你只想要:

return self.__class__({value: key for key, value in self.items()})
Run Code Online (Sandbox Code Playgroud)

一般不会失败:

>>> dict({1:2,3:4})
{1: 2, 3: 4}
    
Run Code Online (Sandbox Code Playgroud)

就个人而言,我会采用您的第一个实现,而不会不必要地浪费 2 倍所需的空间,并进行不必要的第二遍。

请注意,您可能永远不会使用**解包来初始化 dict,构造函数的关键字参数形式对于编写以下内容很方便:

>>> dict(foo=1, bar=2)
{'foo': 1, 'bar': 2}
Run Code Online (Sandbox Code Playgroud)

您甚至可以在复制字典但想要为特定字符串键强制一个值时使用这个方便的技巧:

>>> dict({'foo': 1, 'bar': 2}, bar=42)
{'foo': 1, 'bar': 42}
Run Code Online (Sandbox Code Playgroud)