Я думаю, что это связано с ограничением использования эвристики mypy для перечисления пропущенных членов протокола . Обычно mypy должен сообщать о любых пропущенных элементах протокола, но во избежание генерации слишком большого количества спам-сообщений об ошибках не стоит делать это, если пропущен каждый из элементов протокола или если количество пропущенных элементов превышает 2.
Например, если мы настроим ваш пример так, чтобы он соответствовал этим ограничениям ...
from typing import Protocol
from abc import abstractmethod
class Frobbable(Protocol):
@abstractmethod
def frob(self) -> None:
raise NotImplementedError
@abstractmethod
def bob(self) -> None:
raise NotImplementedError
def main(knob: Frobbable) -> None:
knob.frob()
class BrokenKnob:
def frob(self) -> None:
raise NotImplementedError
main(BrokenKnob())
... мы получим более описательное сообщение об ошибке, как и ожидалось:
test.py:23: error: Argument 1 to "main" has incompatible type "BrokenKnob"; expected "Frobbable"
test.py:23: note: 'BrokenKnob' is missing following 'Frobbable' protocol member:
test.py:23: note: bob
Хотя эти эвристики кажутся разумными, я также думаю, что они могли бы, возможно, сделать с некоторыми дополнительными усовершенствованиями, чтобы лучше обрабатывать сценарии использования, такие как тот, с которым вы сталкиваетесь. Например, если все члены отсутствуют, я думаю, что для mypy было бы разумным сообщить об ошибке «этот объект ничего не реализует в протоколе» вместо более обобщенного c и, возможно, обработать случаи, когда слишком много пропавших без вести более изящно. Возможно, вы могли бы попытаться представить PR для улучшения этой эвристики, если вы готовы к этому?
Если у вас нет времени, вы можете попытаться сделать один из обходных путей, чтобы получить полный список:
- Убедитесь, что все члены Frobbable являются абстрактными (что вы уже делаете)
- Make BrokenKnob временно подкласс Frobbable
- Попробуйте временно создать новый экземпляр BrokenKnob.
Получившаяся ошибка, кажется, перечисляет все отсутствующие атрибуты без фиксированного ограничения.
error: Cannot instantiate abstract class 'BrokenKnob' with abstract attribute 'frob'
Затем, как только вы закончите sh, внося исправления, Вы можете отменить ваши временные изменения.