【发布时间】:2021-10-24 14:03:53
【问题描述】:
考虑下面的代码
import contextlib
import abc
import asyncio
from typing import AsyncContextManager, AsyncGenerator, AsyncIterator
class Base:
@abc.abstractmethod
async def subscribe(self) -> AsyncContextManager[AsyncGenerator[int, None]]:
pass
class Impl1(Base):
@contextlib.asynccontextmanager
async def subscribe(self) -> AsyncIterator[ AsyncGenerator[int, None] ]: <-- mypy error here
async def _generator():
for i in range(5):
await asyncio.sleep(1)
yield i
yield _generator()
对于Impl1.subscribe mypy 给出错误
Signature of "subscribe" incompatible with supertype "Base"
在上述情况下指定类型提示的正确方法是什么?还是 mypy 错了?
【问题讨论】:
-
作为一种解决方法,您可以将
def _generator()抽象化并在Base' by calling_generator(). Then inImpl1` 中实现subscribe实现def _generator()。 -
您甚至不需要将
_generator放入Base,您可以在没有装饰器的情况下在Impl1中拥有一个私人_subscribe(其中包含您当前@987654333 的内容) @) 然后从实际的subscribe返回contextlib.asynccontextmanager(self._subcribe())。我怀疑问题是 mypy 不喜欢你用装饰器更改类型签名,这看起来很奇怪,因为它是一个 stdlib 装饰器 -
@Wombatz 我简化了代码。在我的代码中,
yield generator()在 try 中受到保护,除了子类特定的初始化和清理代码。所以这是行不通的。 -
@joel 没错,我记得读到 mypy 原则上应该与异步上下文管理器一起使用。但这可能是一个错误,或者我犯了一个错误。
标签: python type-hinting mypy