如何正确标注返回生成器上下文管理器的可调用类型?
正确的类型标注方案及实现说明
替代内部API的类型选择
别用下划线开头的_GeneratorContextManager——这是CPython的内部实现细节,不属于公开API,随时可能变更。直接用标准库公开的contextlib.ContextManager(或contextlib.AbstractContextManager)来定义返回类型即可,这是官方推荐的公开类型。
修改后的代码示例
from contextlib import contextmanager, ContextManager from typing import Callable, Generator # 用公开的ContextManager替代内部API WrapperType = Callable[[int, str], ContextManager[None]] def wrapper() -> WrapperType: @contextmanager def inner(some_int: int, some_str: str) -> Generator[None, None, None]: # 这里可以注入pytest fixture,比如直接引用外层作用域的fixture变量 yield return inner
为什么BadWrapperType不符合要求
@contextmanager装饰器的作用就是把生成器函数转换成返回上下文管理器对象的函数,而非返回原始生成器。所以wrapper返回的inner函数,实际返回值是ContextManager实例,不是Generator,Pylance的错误提示是合理的。
这种实现方式是否推荐
在pytest中用这种wrapper模式注入fixture是完全可行的,属于常见的上下文管理器逻辑复用方案。你可以在wrapper里获取pytest的fixture(比如通过request fixture),传递给inner函数,或者让inner直接访问外层wrapper作用域的fixture变量,以此将fixture逻辑封装成可复用的上下文管理器。
额外语法优化(Python 3.10+)
如果项目使用Python 3.10及以上版本,可利用PEP 604的联合类型语法简化标注:
from contextlib import contextmanager, ContextManager from typing import Callable, Generator WrapperType = Callable[[int, str], ContextManager[None]] def wrapper() -> WrapperType: @contextmanager def inner(some_int: int, some_str: str) -> Generator[None, None, None]: yield return inner
内容的提问来源于stack exchange,提问作者IMCoins
相关产品推荐
相关产品推荐

