带类型注解的异步装饰器结合asyncio.run的mypy类型错误问题
async装饰器的mypy类型报错问题
问题代码
from typing import Awaitable, Callable, ParamSpec, TypeVar import asyncio P = ParamSpec("P") R = TypeVar("R") def a_decorator(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[R]]: async def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R: print("wrapped") return await func(*args, **kwargs) return _wrapper @a_decorator async def just_a_function(value1: int) -> bool: print(value1) return isinstance(value1, int) # mypy报错: # Argument 1 to "run" has incompatible type "Awaitable[bool]"; expected "Coroutine[Any, Any, <nothing>]" [arg-type] asyncio.run(just_a_function(10))
报错原因
asyncio.run()的参数类型要求是Coroutine[Any, Any, T],而你定义的装饰器返回的是更宽泛的Callable[P, Awaitable[R]]。尽管Coroutine是Awaitable的子类,但mypy对该场景的类型检查较为严格——它需要明确的协程类型,而非通用的可等待对象类型。
解决方案
调整装饰器的类型标注,将返回值的Awaitable[R]替换为具体的Coroutine[Any, Any, R],让类型匹配asyncio.run()的要求:
from typing import Callable, ParamSpec, TypeVar, Coroutine, Any import asyncio P = ParamSpec("P") R = TypeVar("R") def a_decorator(func: Callable[P, Coroutine[Any, Any, R]]) -> Callable[P, Coroutine[Any, Any, R]]: async def _wrapper(*args: P.args, **kwargs: P.kwargs) -> R: print("wrapped") return await func(*args, **kwargs) return _wrapper @a_decorator async def just_a_function(value1: int) -> bool: print(value1) return isinstance(value1, int) asyncio.run(just_a_function(10)) # mypy不再报错
选择建议
不要保持原有的Awaitable[R]标注,应该遵循mypy的提示调整为Coroutine类型。这样做既能通过类型检查,也能让代码的类型约束更精确——毕竟被装饰的是async def定义的协程函数,返回的本来就是协程对象,而非通用的可等待对象。
如果你的装饰器需要兼容返回Future等其他Awaitable类型的函数,可以在调用asyncio.run()时添加类型忽略注释# type: ignore[arg-type],但这属于妥协方案,优先推荐精确匹配协程类型的写法。
内容的提问来源于stack exchange,提问作者sanders
相关产品推荐
相关产品推荐

