如何为强制关键字参数转换为可选关键字参数编写装饰器类型?

0 投票
0 回答
28 浏览
提问于 2025-04-12 01:52

我有很多函数,它们的结构和基本参数都差不多:

async def get_stuff_from_external_api(*, client: Client | None, id: int) -> Ressource:
    if not client:
        client = make_client()
    return Ressource(await client.get(id))

为了让我的代码更简洁,我把这个逻辑提取成了一个装饰器,现在这个装饰器和函数都是:

def external_api_decorator(func):
    @functools.wraps(func)
    def wrapped_func(*args, **kwargs):
        client = kwargs.pop(client, None)
        if not client:
            client = make_client()
        return await func(*args, client=client, **kwargs)
    return inner

@external_api_decorator
async def get_stuff_from_external_api(*, client: Client, id: int) -> Ressource:
    return Ressource(await client.get(id))

我现在的问题是,我无法正确地给 external_api_decorator 添加类型,这样就无法保留被装饰函数的初始参数(在我的例子中是 id)和返回值(在我的例子中是 Ressource)。

我尝试了很多解决方案(比如 ProtocolGenericParamSpec 等等),但我觉得我卡在了 Concatenate/ParamSpec 不支持关键字参数上。我是不是漏掉了什么?这看起来是一个非常经典的用例。

这里有一个 mypy 的在线测试环境,可以复现这个问题。

0 个回答

暂无回答

撰写回答