查找最小值时为 dict 键入提示

Type hints for dict when finding min value

以下代码,根据其键查找字典的最小值:

from typing import Dict

a: Dict[str, float] = {'a': 1, 'b': 2, 'c': 3}
min(a, key=a.get)

引发 mypy 错误:

Value of type variable "SupportsLessThanT" of "min" cannot be "Optional[float]"

这似乎表明Dict中定义的类型是Optional。如何让上面的代码通过 mypy 测试?我已尝试检查以确保 none 的值是 None,但这不起作用:

# Does not work
if any([x is None for x in a.values()]):
    raise ValueError('foo')
else:
    min(a, key=a.get)

如何用最少的代码使这段代码通过 mypy 测试?

MyPy 不满意的原因是,作为 Mapping,字典的 get 方法 return 是值的 可选 使用单个参数调用时的类型。例如。见 the typeshed definition:

class Mapping(_Collection[_KT], Generic[_KT, _VT_co]):
    # ...
    @overload
    def get(self, key: _KT) -> Optional[_VT_co]: ...
    @overload
    def get(self, key: _KT, default: Union[_VT_co, _T]) -> Union[_VT_co, _T]: ...

在没有 default 值的情况下,如果密钥不存在,get 可以 return None在字典里。在你的情况下,这永远不会发生,因为你总是使用 are 存在的键,但是 types 不知道!

不幸的是,例如,断言 Python 中的值的类型是相当尴尬的。您可以通过将方法分配给 Any 类型的变量来有效地擦除类型:

getter: Any = a.get
min(a, key=getter)

但这似乎不太安全。另一种选择是使用调用 __getitem__ 的实现,它总是 return 值类型(__getitem__(self, k: _KT) -> _VT_co 来自与上述相同的来源):

min(a, key=lambda k: a[k])