python - 通过 ParamSpec 输入一个接受参数的装饰器(PEP-612,Python 3.10)
问题描述
我正在阅读PEP-612,它使输入装饰器变得相当容易处理。此外,PEP 中提供的示例使其看起来非常简单。此示例直接从 PEP 复制:
from typing import ParamSpec, TypeVar
from collections.abc import Callable, Awaitable
P = ParamSpec("P")
R = TypeVar("R")
def add_logging(f: Callable[P, R]) -> Callable[P, Awaitable[R]]:
async def inner(*args: P.args, **kwargs: P.kwargs) -> R:
await log_to_database()
return f(*args, **kwargs)
return inner
@add_logging
def takes_int_str(x: int, y: str) -> int:
return x + 7
await takes_int_str(1, "A") # Accepted
await takes_int_str("B", 2) # Correctly rejected by the type checker
但是,我发现正确键入注释可参数化装饰器并非易事。检查以下 MRE:
import functools
import inspect
from collections.abc import Callable, Coroutine
from typing import ParamSpec, TypeVar
P = ParamSpec("P")
R = TypeVar("R")
def tag(*names: str) -> ??:
"""This decorator just tags an async function with the provided name(s)."""
for name in names:
if not isinstance(name, str):
raise TypeError("tag name must be a string")
def outer(func: Callable[P, R]) -> Callable[P, Coroutine[R]]:
func.tags = names
if not inspect.iscoroutinefunction(func):
raise TypeError("tagged function must be an async function")
@functools.wraps(func)
async def inner(*args: P.args, **kwargs: P.kwargs) -> R:
result = await func(*args, **kwargs)
return result
return inner
return outer
我正在努力找出tag
函数的返回类型。另外,我对函数类型outer
和inner
嵌套函数的正确性不是 100% 有信心。如何正确输入?
PS 我知道,截至今天,mypy 0.902 还不完全支持此功能。
解决方案
首先要注意的是,您的参数化装饰器示例不仅仅是 PEP 的装饰器示例加上参数化。相反,您的第二个示例的装饰器(在参数化之后)采用异步函数,而 PEP 的示例采用同步函数。
因为您直接await
ingfunc
的结果,与 PEP 的示例不同,PEP 的示例await
编辑了一个单独的记录器,然后f
正常调用,您outer
需要使用 aCallable[[P], Awaitable[R]]
而不是Callable[[P], R]
.
第二点要注意的是,关于tag
s 返回类型,你可以通过添加 来reveal_type(outer)
计算,这反过来将是 的返回类型tag
。我还没有运行这个(因为mypy
实际上还没有支持你的例子),但它应该说Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]
. 换句话说,tag
返回一个装饰器,它本身接受一个异步函数并返回一个异步函数。
要注意的第三件事是,您可能希望Awaitable[T]
在所有示例中都使用它(这就是我自己在上面一直使用它的原因)而不是Coroutine[T]
. 这是因为 a)Coroutine
采用三个类型参数而不是一个(因此您必须使用Coroutine[Any, Any, T]
而不是Coroutine[T]
,其中前两个类型参数用于send)并且 b)Coroutine
是添加了ing支持的子类型,您不需要无论如何都不要使用。Awaitable
send
推荐阅读
- reactjs - React Styled Components 生成过多的 css
- html - 放大页面时标题和文本隐藏在我的滑块后面
- r - lme4 用于多元混合模型 - 永远不会收敛/完成执行
- java - 在 Itext 报告中使用 PdfPTable 时未显示数据
- android - iOS 中的 AlarmManager 替代品
- asp.net - 无法返回employeeType,但我可以获取displayName
- python - 无法在产品页面中找到链接
- sql - SQL:仅当多个值是 CatalogTable 中的 IN 1 列时才选择
- typescript - 当组件具有非法类型时,使用 TypeScript 创建 React App 中的 Storybook 仍然可以编译
- r - 为什么Rmarkdown中的Knit期间一段R代码不起作用