异步装饰器问题:Pylance无法识别被装饰函数为可等待对象
问题:异步装饰器的类型提示修复
为方便运行阻塞代码,我编写了一个异步装饰器,将阻塞代码放入单独线程执行,代码示例如下:
from functools import wraps import time import asyncio def async_wrapper(func): @wraps(func) async def wrapper(*args, **kwargs): print("wrapper") return await asyncio.to_thread(func, *args, **kwargs) return wrapper @async_wrapper def blocking_code(): print("Start") time.sleep(5) print("end") await blocking_code() # type issue
运行结果正常:
wrapper Start end
但在VSCode(Python 3.10)中,Pylance提示以下警告:
"None" is not awaitable
"None" is incompatible with protocol "Awaitable[_T_co@Awaitable]"
"await" is not present PylancereportGeneralTypeIssues
(function) def blocking_code() -> None
开启严格类型检查模式后,返回类型显示为Unknown,警告仍存在:
{ "python.analysis.typeCheckingMode": "strict" }
需要修复该类型提示问题,且避免每次创建仅调用私有阻塞函数的公开异步函数。
解决方案
问题根源在于装饰器缺少类型注解,导致类型检查器无法识别被装饰后的函数已变为可等待的异步函数。通过添加类型提示注解即可解决:
1. 为装饰器添加完整类型注解
使用typing模块的Callable、TypeVar、Awaitable等类型,明确装饰器的输入输出类型:
from functools import wraps import time import asyncio from typing import Callable, TypeVar, Awaitable # 定义类型变量,保留原函数的返回类型 T = TypeVar('T') def async_wrapper(func: Callable[..., T]) -> Callable[..., Awaitable[T]]: @wraps(func) async def wrapper(*args, **kwargs) -> T: print("wrapper") return await asyncio.to_thread(func, *args, **kwargs) return wrapper @async_wrapper def blocking_code() -> None: print("Start") time.sleep(5) print("end") await blocking_code()
注解说明:
Callable[..., T]:表示原函数是可接受任意参数、返回类型为T的可调用对象Callable[..., Awaitable[T]]:表示装饰后的函数返回Awaitable[T],即支持await的异步函数async def wrapper(...) -> T:明确异步包装函数的返回类型与原函数一致
2. 验证效果
添加类型注解后,Pylance会正确识别blocking_code()的返回类型为Awaitable[None],不再提示"None is not awaitable"的警告,严格类型检查模式下也能正常识别类型。
这种方式既解决了类型提示问题,又无需额外创建仅调用阻塞函数的异步函数,符合需求。
内容的提问来源于stack exchange,提问作者BPDev
相关产品推荐
相关产品推荐

