从函数的关键字参数生成TypedDict

2024-03-29 11:55:15 发布

您现在位置:Python中文网/ 问答频道 /正文

foo.py

kwargs = {"a": 1, "b": "c"}

def consume(*, a: int, b: str) -> None:
    pass

consume(**kwargs)

mypy foo.py

error: Argument 1 to "consume" has incompatible type "**Dict[str, object]"; expected "int"
error: Argument 1 to "consume" has incompatible type "**Dict[str, object]"; expected "str"

这是因为objectintstr的超类型,因此可以推断。如果我声明:

from typing import TypedDict

class KWArgs(TypedDict):
    a: int
    b: str

然后将kwargs注释为KWArgsmypy检查通过。这实现了类型安全,但需要我在KWArgs中复制consume的关键字参数名称和类型。有没有一种方法可以在类型检查时从函数签名生成这个TypedDict,这样我就可以最小化维护中的重复


Tags: topy类型objectfooerrorargumentkwargs
1条回答
网友
1楼 · 发布于 2024-03-29 11:55:15

据我所知,在这方面没有直接的解决办法,但有另一种优雅的方法来实现这一点:

我们可以利用typingsNamedTuple创建一个包含参数的对象:

ConsumeContext = NamedTuple('ConsumeContext', [('a', int), ('b', str)])

现在,我们定义consume方法以接受它作为参数:

def consume(*, consume_context : ConsumeContext) -> None:
    print(f'a : {consume_context.a} , b : {consume_context.b}')

整个守则是:

from typing import NamedTuple

ConsumeContext = NamedTuple('ConsumeContext', [('a', int), ('b', str)])

def consume(*, consume_context : ConsumeContext) -> None:
    print(f'a : {consume_context.a} , b : {consume_context.b}')

ctx = ConsumeContext(a=1, b='sabich')

consume(consume_context=ctx)

运行mypy将产生:

Success: no issues found in 1 source file

它将认识到ab是参数,并批准这一点

运行代码将输出:

a : 1 , b : sabich

但是,如果我们将b更改为非字符串,mypy将抱怨:

foo.py:9: error: Argument "b" to "ConsumeContext" has incompatible type "int"; expected "str"
Found 1 error in 1 file (checked 1 source file)

这样,我们通过定义一次方法的参数和类型来实现方法的类型检查

[1]因为如果基于另一个定义TypedDict或函数签名,则需要知道另一个的__annotations__,这在检查时是未知的,而定义一个在运行时强制转换类型的修饰符将错过类型检查的点。

相关问题 更多 >