Python 类型提示和上下文管理器 [英] Python type hints and context managers

查看:32
本文介绍了Python 类型提示和上下文管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

应该如何使用 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 的存根:https://github.com/python/typeshed/blob/master/stdlib/contextlib.pyi

We can find the stubs for contextlib here: https://github.com/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?

这是因为 GeneratorIterator 的子类型——我们可以再次自己检查一下 通过咨询 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 类型提示和上下文管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆