mypy设置字典键/接口



假设我有一个函数,它将字典作为参数:

def f(d: dict) -> None:
x = d["x"]
print(x)

我可以指定此字典必须具有 mypy 的键"x"吗?我正在寻找类似于打字稿界面的东西,而无需将d更改为类。

我不想将d更改为类的原因是因为我正在修改现有的大型代码库以添加mypy类型检查,并且该字典在很多地方都使用。如果我必须将所有d["x"]实例更改为d.x,我将不得不修改很多代码。

从 Python 3.8 开始,您可以使用typing.TypedDict,根据 PEP 589 添加。对于较旧的 Python 版本,您可以使用typing-extensions

请注意,PEP 确实承认更好的选择是在此用例中使用数据类,但是:

Dataclasses 是解决此用例的最新替代方法,但在 dataclasses 可用之前仍然有很多现有代码,尤其是在大型现有代码库中,类型提示和检查已被证明是有帮助的。

因此,更好的答案考虑不同的数据结构,例如命名元组或数据类,您可以在其中指定类型具有的属性。这就是打字稿声明的作用,实际上:

printLabel函数具有单个参数,该参数要求传入的对象具有一个名为label的字符串类型的属性。

Python 属性在道德上等同于 Typescript 对象属性。Typescript 对象符号和 Python 字典有很多共同点可能会混淆问题,但是在尝试将概念映射到 Python 时,您不应该将 Typescript 对象声明视为类以外的任何东西。

这可能看起来像这样:

from dataclasses import dataclass
@dataclass
class SomeClass:
x: str
def f(sc: SomeClass) -> None:
x = sc.x
print(x)

也就是说,您可以在此处使用typing.TypedDict

from typing import TypedDict
class SomeDict(TypedDict):
x: str
def f(d: SomeDict) -> None:
x = d['x']
print(x)

TypeDict声明中的键要么是必需的,要么都是可选的(当您在声明上设置total=False时(;您必须使用继承来生成具有某些可选键的类型,请参阅链接的文档。请注意,TypedDict当前存在混合使用可选键和必需键的问题;即使使用 Python 3.8,您可能也希望使用typing-extensions包将 Python 3.9 版本(修复此问题(作为向后移植。只需使用from typing_extensions import TypedDict而不是上述from typing ...导入,typing-extensions包在适当的时候回退到标准库版本。

Mypy 通过提供TypedDict类型扩展了 PEP 484。这允许指定字典类型的特定属性。在您的情况下,您可以执行以下操作:

from mypy_extensions import TypedDict
# you can also do HasX = TypedDict('HasX', {'x': str})
class HasX(TypedDict):
x: str
def f(x: HasX) -> None:
reveal_type(d["x"])  # error: Revealed type is 'builtins.str'

最新更新