[英]Type hinting a Python contextmanager with arguments
我有以下上下文管理器:
@contextmanager
def timed_task(task_name: str, **context_info)
pass
现在我有 function
def my_func(my_timed_task: Any):
with my_timed_task("my_func_task", foo="bar"):
pass
我将如何键入提示my_func
以便它知道my_timed_task
是类型为timed_task(task_name: str, **kwargs)
的上下文管理器,或具有相同 arguments 的任何等效上下文管理器?
我知道contextlib.AbstractContextManager
但我可以找到解释如何将它与 contextmanager arguments 结合使用的文档,而不仅仅是无参数的上下文管理器。
所以我在这里做一些假设来提供一个完整的答案。 如果其中任何一个不正确,您将不得不相应地调整代码。 我假设:
timed_task
和my_func
都可以返回任何类型。**context_info
kwargs 可以是任何类型。 这里要理解的重要一件事是,您装饰的 function 本身不是上下文管理器。 它是一个工厂function,它返回一个上下文管理器,即一个 object,它的__enter__
和__exit__
方法定义为在with
语句中使用。 (见文档)
在手头的事情上,你基本上有两个选择。
在我看来,第一个在技术上是“最正确”的,但在您的情况以及许多其他情况下也可能是矫枉过正,首先定义您自己的Protocol
:
from contextlib import contextmanager, AbstractContextManager
from typing import Any, Protocol
class MyContextManagerFactory(Protocol):
def __call__(self, task_name: str, **context_info: Any) -> AbstractContextManager[Any]: ...
@contextmanager
def timed_task(task_name: str, **context_info: Any) -> Any:
pass
def my_func(my_timed_task: MyContextManagerFactory) -> Any:
with my_timed_task("my_func_task", foo="bar"):
pass
这有mypy
pass(在--strict
模式下)没有问题。
此处需要协议的原因是因为您的上下文管理器工厂中允许使用任意关键字 arguments **context_info
,并且据我所知,目前无法相应地指定Callable
类型。
对你的类型如此迂腐的好处是,像 PyCharm 这样的 IDE 会给你准确的提示,不仅是关于什么my_timed_task
是什么类型的参数名称,但实际上是允许的。
您的第二个选项要简单得多,但也不那么精确。 您可以简单地将my_timed_task
的类型定义为可调用的,接受任何内容并返回您的上下文管理器:
from contextlib import contextmanager, AbstractContextManager
from typing import Any, Callable
@contextmanager
def timed_task(task_name: str, **context_info: Any) -> Any:
pass
def my_func(my_timed_task: Callable[..., AbstractContextManager[Any]]) -> Any:
with my_timed_task("my_func_task", foo="bar"):
pass
也让mypy
开心。 但是,没有关于您的my_timed_task
工厂接受什么 arguments 的信息,因此您的 IDE 不会抱怨这样做:
def my_func(my_timed_task: Callable[..., AbstractContextManager[Any]]) -> Any:
with my_timed_task(1, 3, "a", True):
pass
您选择哪一个选项显然取决于您,并且取决于您想要的精确度。
希望这可以帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.