带有异步上下文管理器的 Python 抽象方法

标签 python python-3.x python-asyncio mypy

我有几个速率限制器类(一个未显示),我想为其创建 ABC。 request 方法是一个异步上下文管理器。通过下面显示的代码,我得到了

Signature of "request" incompatible with supertype "RateLimiterInterface"

如果我尝试用 @asynccontextmanager 修饰抽象方法,我会得到一个输入错误:

Argument 1 to "asynccontextmanager" has incompatible type "Callable[[RateLimiterInterface], Coroutine[Any, Any, AsyncIterator[Any]]]"; expected "Callable[..., AsyncIterator[]]"

我该怎么做?

class RateLimiterInterface(abc.ABC):
    @abc.abstractmethod
    async def request(self) -> AsyncIterator:
        pass

class LeakyBucketRateLimiter(RateLimiterInterface):
    def __init__(self, max_tokens: Optional[int] = None, rate: float = 60) -> None:
        self.max_tokens = max_tokens
        self.rate = rate
        self._bucket = max_tokens
        self._last_added_at = time.time()

    @contextlib.asynccontextmanager
    async def request(self) -> AsyncIterator:
        if self._bucket is None:
            yield
            return
        while not self._bucket:
            await asyncio.sleep(0)
            self._add_tokens(int((time.time() - self._last_added_at) * self.rate))
        self._bucket -= 1
        yield
        return

    def _add_tokens(self, num_tokens: int) -> None:
        if num_tokens == 0:
            return
        self._bucket += num_tokens
        if self._bucket > self.max_tokens:
            self._bucket = self.max_tokens
        self._last_added_at = time.time()

最佳答案

我只是在打字时遇到了同样的问题,然后就这样解决了:

import abc
import contextlib
import asyncio


class TestAbstract(metaclass=abc.ABCMeta):
    @contextlib.asynccontextmanager
    @abc.abstractmethod
    # Here the trick: you must declare an  asynchronous generator function,
    # not a regular coroutine function so it have to explicitly yield.
    async def foo(self):
        yield


class SubTest(TestAbstract):
    @contextlib.asynccontextmanager
    async def foo(self):
        yield


async def test_coro():
    async with SubTest().foo():
        print('OK')


asyncio.run(test_coro())

关于带有异步上下文管理器的 Python 抽象方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54204990/

相关文章:

python - 如何在 python 中捕获所有旧式类异常?

python-3.x - python-vlc无法播放并通过youtube视频链接做出响应吗?

python - 读取 PEM 字符串时出现 PyAsn1 错误

python - 如何使用 asyncio 同时运行无限循环?

python - 在不同的事件循环中竞速两个任务

python - 从 URL 获取参数 slugs

python - python读取大型二进制文件最有效的方法是什么

python - 有什么工具可以为 python 包交叉创建 OSX 安装程序?

python - 如何在 Python 3.6 中验证 AWS Cognito 生成的 JWT 的签名?

python - future 内部循环的状态始终处于待定状态