假设我有一个以字典作为参数的函数:
def f(d: dict) -> None:
x = d["x"]
print(x)
我可以指定这个字典必须有mypy的密钥
"x"
吗?我正在寻找类似于 typescript 的界面,而不将 d
更改为类。
我不想将
d
更改为类的原因是因为我正在修改大型现有代码库以添加 mypy
类型检查,并且该字典在很多地方使用。如果我必须将 d["x"]
的所有实例更改为 d.x
,我就必须修改大量代码。
typing.TypedDict
,根据 PEP 589 添加。对于较旧的 Python 版本,您可以使用 typing-extensions
包
请注意,PEP 确实承认更好的选择是针对此用例使用 dataclasses,但是:
数据类是解决此用例的最新替代方案,但仍然有许多现有代码是在数据类可用之前编写的,特别是在类型提示和检查已被证明很有帮助的大型现有代码库中。
因此,更好的答案是考虑不同的数据结构,例如命名元组或数据类,您可以在其中指定类型具有的属性。这就是打字稿声明的作用,真的:
Python 属性在道德上等同于 Typescript 对象属性。 Typescript 对象表示法和 Python 字典有很多共同点,这可能会让人感到困惑,但是在尝试将概念映射到 Python 时,您不应该将 Typescript 对象声明视为类以外的任何东西。
printLabel
函数有一个参数,要求传入的对象有一个名为label
的字符串类型的属性。
可能看起来像这样:
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
包就会在适当的时候回退到标准库版本。
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'