mypy 设置字典键/接口
mypy set dictionary keys / interface
假设我有一个将字典作为参数的函数:
def f(d: dict) -> None:
x = d["x"]
print(x)
我可以指定这个字典 必须 有 mypy 的键 "x"
吗?我正在寻找类似于 interface from typescript 的内容,但没有将 d
更改为 class。
我不想将 d
更改为 class 的原因是因为我正在修改一个大型现有代码库以添加 mypy
类型检查并且使用了这个字典在许多地方。如果我必须将 d["x"]
的所有实例更改为 d.x
.
,我将不得不修改大量代码
从 Python 3.8 开始,您可以使用 typing.TypedDict
, added as per PEP 589. For older Python versions you can use the typing-extensions
package
请注意,PEP 确实承认更好的选择是您对此用例使用 data类,但是:
Dataclasses are a more recent alternative to solve this use case, but there is still a lot of existing code that was written before dataclasses became available, especially in large existing codebases where type hinting and checking has proven to be helpful.
所以更好的答案是考虑不同的数据结构,例如命名元组或数据类,您可以在其中指定类型具有的属性。这就是打字稿声明所做的,真的:
The printLabel
function has a single parameter that requires that the object passed in has a property called label
of type string.
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
currently has issues with a mix of optional and required keys;即使在使用 Python 3.8 时,您可能希望使用 typing-extensions
包来获取 Python 3.9 版本(修复此问题)作为向后移植。只需使用 from typing_extensions import TypedDict
而不是上面的 from typing ...
导入,typing-extensions
包会在适当的时候回退到标准库版本。
Mypy 通过提供 TypedDict
类型扩展了 PEP 484。这允许指定 dict 类型的特定属性。在您的情况下,您可以执行以下操作:
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'
假设我有一个将字典作为参数的函数:
def f(d: dict) -> None:
x = d["x"]
print(x)
我可以指定这个字典 必须 有 mypy 的键 "x"
吗?我正在寻找类似于 interface from typescript 的内容,但没有将 d
更改为 class。
我不想将 d
更改为 class 的原因是因为我正在修改一个大型现有代码库以添加 mypy
类型检查并且使用了这个字典在许多地方。如果我必须将 d["x"]
的所有实例更改为 d.x
.
从 Python 3.8 开始,您可以使用 typing.TypedDict
, added as per PEP 589. For older Python versions you can use the typing-extensions
package
请注意,PEP 确实承认更好的选择是您对此用例使用 data类,但是:
Dataclasses are a more recent alternative to solve this use case, but there is still a lot of existing code that was written before dataclasses became available, especially in large existing codebases where type hinting and checking has proven to be helpful.
所以更好的答案是考虑不同的数据结构,例如命名元组或数据类,您可以在其中指定类型具有的属性。这就是打字稿声明所做的,真的:
The
printLabel
function has a single parameter that requires that the object passed in has a property calledlabel
of type string.
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
currently has issues with a mix of optional and required keys;即使在使用 Python 3.8 时,您可能希望使用 typing-extensions
包来获取 Python 3.9 版本(修复此问题)作为向后移植。只需使用 from typing_extensions import TypedDict
而不是上面的 from typing ...
导入,typing-extensions
包会在适当的时候回退到标准库版本。
Mypy 通过提供 TypedDict
类型扩展了 PEP 484。这允许指定 dict 类型的特定属性。在您的情况下,您可以执行以下操作:
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'