如何键入注释字典理解?

How to type annotate dict comprehension?

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

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

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()})

为了开玩笑,我尝试了 return self.__class__({value: key for key, value in self.items()}),它似乎工作相同并通过了 mypy 检查。 TIL dicts 可以用字典而不是 **kwargs.

初始化

MyPy 在这里是正确的,它 在你的实现中捕获了一个错误(静态类型检查的优点)。类型:

{value: key for key, value in self.items()}

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

dict(**some_mapping)

其中键不能保证是字符串

观察:

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

你只想:

return self.__class__({value: key for key, value in self.items()})

一般不会失败:

>>> dict({1:2,3:4})
{1: 2, 3: 4}
    

就我个人而言,我会选择你的第一个实现,而不考虑不必要地浪费 2 倍的 space 所需的数量,并进行不必要的第二次传递。

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

>>> dict(foo=1, bar=2)
{'foo': 1, 'bar': 2}

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

>>> dict({'foo': 1, 'bar': 2}, bar=42)
{'foo': 1, 'bar': 42}