Я пытаюсь извлечь шаблон, который мы используем в нашей базе кода, в более общую конструкцию многократного использования. Однако я не могу заставить аннотации общего типа работать с mypy.
Вот что я получил:
from abc import (
ABC,
abstractmethod
)
import asyncio
import contextlib
from typing import (
Any,
Iterator,
Generic,
TypeVar
)
_TMsg = TypeVar('_TMsg')
class MsgQueueExposer(ABC, Generic[_TMsg]):
@abstractmethod
def subscribe(self, subscriber: 'MsgQueueSubscriber[_TMsg]') -> None:
raise NotImplementedError("Must be implemented by subclasses")
@abstractmethod
def unsubscribe(self, subscriber: 'MsgQueueSubscriber[_TMsg]') -> None:
raise NotImplementedError("Must be implemented by subclasses")
class MsgQueueSubscriber(Generic[_TMsg]):
@contextlib.contextmanager
def subscribe(
self,
msg_queue_exposer: MsgQueueExposer[_TMsg]) -> Iterator[None]:
msg_queue_exposer.subscribe(self)
try:
yield
finally:
msg_queue_exposer.unsubscribe(self)
class DemoMsgQueSubscriber(MsgQueueSubscriber[int]):
pass
class DemoMsgQueueExposer(MsgQueueExposer[int]):
# The following works for mypy:
# def subscribe(self, subscriber: MsgQueueSubscriber[int]) -> None:
# pass
# def unsubscribe(self, subscriber: MsgQueueSubscriber[int]) -> None:
# pass
# This doesn't work but I want it to work :)
def subscribe(self, subscriber: DemoMsgQueSubscriber) -> None:
pass
def unsubscribe(self, subscriber: DemoMsgQueSubscriber) -> None:
pass
Я прокомментировал какой-то код, который работает, но не полностью удовлетворяет мои потребности. В основном я хочу, чтобы DemoMsgQueueExposer
DemoMsgQueSubscriber
в своих методах subscribe
и DemoMsgQueSubscriber
unsubscribe
. Тип кода отлично проверяется, если я использую MsgQueueSubscriber[int]
как тип, но я хочу, чтобы он принимал подтипы этого.
Я продолжаю сталкиваться со следующей ошибкой.
generic_msg_queue.py:55: error: Argument 1 of "subscribe" incompatible with supertype "MsgQueueExposer"
Я чувствую, что это имеет какое-то отношение к co-/контравариантам, но я попробовал несколько вещей, прежде чем я сдался и пришел сюда.