应该如何使用 Python 类型提示注释上下文管理器?
How should a context manager be annotated with Python type hints?
import typing @contextlib.contextmanager def foo() -> ???: yield关于 contextlib 的文档 没有过多提及类型.
关于 Typing.ContextManager 的文档 还不止这些也有帮助.
The documentation on typing.ContextManager is not all that helpful either.
还有 typing.Generator,至少有一个例子.这是否意味着我应该使用 typing.Generator[None, None, None] 而不是 typing.ContextManager?
There's also typing.Generator, which at least has an example. Does that mean I should use typing.Generator[None, None, None] and not typing.ContextManager?
import typing @contextlib.contextmanager def foo() -> typing.Generator[None, None, None]: yield 推荐答案每当我不能 100% 确定函数接受什么类型时,我喜欢咨询 typeshed,这是 Python 类型提示的规范存储库.例如,Mypy 直接捆绑并使用 typeshed 来帮助它执行其类型检查.
Whenever I'm not 100% sure what types a function accepts, I like to consult typeshed, which is the canonical repository of type hints for Python. Mypy directly bundles and uses typeshed to help it perform its typechecking, for example.
我们可以在这里找到 contextlib 的存根:github/python/typeshed/blob/master/stdlib/contextlib.pyi
We can find the stubs for contextlib here: github/python/typeshed/blob/master/stdlib/contextlib.pyi
if sys.version_info >= (3, 2): class GeneratorContextManager(ContextManager[_T], Generic[_T]): def __call__(self, func: Callable[..., _T]) -> Callable[..., _T]: ... def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., GeneratorContextManager[_T]]: ... else: def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., ContextManager[_T]]: ...有点不知所措,但我们关心的是这条线:
It's a little overwhelming, but the line we care about is this one:
def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., ContextManager[_T]]: ...它声明装饰器接受一个 Callable[..., Iterator[_T]] —— 一个带有任意参数的函数,返回一些迭代器.所以总而言之,这样做会很好:
It states that the decorator takes in a Callable[..., Iterator[_T]] -- a function with arbitrary arguments returning some iterator. So in conclusion, it would be fine to do:
@contextlib.contextmanager def foo() -> Iterator[None]: yield那么,为什么按照评论的建议使用 Generator[None, None, None] 也有效?
So, why does using Generator[None, None, None] also work, as suggested by the comments?
这是因为 Generator 是 Iterator 的子类型——我们可以再次自己检查一下 通过咨询 typeshed.因此,如果我们的函数返回一个生成器,它仍然与 contextmanager 期望的兼容,因此 mypy 可以毫无问题地接受它.
It's because Generator is a subtype of Iterator -- we can again check this for ourselves by consulting typeshed. So, if our function returns a generator, it's still compatible with what contextmanager expects so mypy accepts it without an issue.
更多推荐
Python 类型提示和上下文管理器
发布评论