Почему mypy не поймет создание экземпляра этого объекта?

#python #type-hinting #mypy #python-typing #abstract-base-class

Вопрос:

Я пытаюсь определить класс, который принимает другой класс в качестве атрибута _model и будет создавать экземпляры объектов этого класса.

 from abc import ABC
from typing import Generic, TypeVar, Any, ClassVar, Type

Item = TypeVar("Item", bound=Any)


class SomeClass(Generic[Item], ABC):
    _model: ClassVar[Type[Item]]

    def _compose_item(self, **attrs: Any) -> Item:
        return self._model(**attrs)
 

Я думаю , должно быть очевидно, что self._model(**attrs) возвращает экземпляр Item , так _model как явно объявлен как Type[Item] и attrs объявлен как Dict[str, Any] .

Но то, что я получаю от mypy 0.910 этого:

 test.py: note: In member "_compose_item" of class "SomeClass":
test.py:11: error: Returning Any from function declared to return "Item"
            return self._model(**attrs)
            ^
 

Что я делаю не так?

Комментарии:

1. вы знаете **attrs: Any , что в любом случае теряется почти вся безопасность типа? Это связано с ответом Алекса: у __init__ из Item может быть любая подпись. Подумывали ли вы о том, чтобы быть более конкретным, например, с Callable[[int, str, bool], Item] (с соответствующими типами аргументов)?

2. Это: bound=Any действительно не имеет никакого смысла… У него просто не должно быть привязки. Any это особый тип, который в основном означает «не вводите, проверьте это». Я не думаю, что даже определено, как он должен работать в качестве привязки для типоразмера.

3. Кроме того, какую версию mypy вы используете? На моей машине mypy 0.910 на самом деле не жалуется… но, как я уже сказал, я не думаю Item = TypeVar("Item", bound=Any) , что это четко определено

4. @juanpa.arrivillaga вы получите ошибку , только если запустите MyPy с --strict настройкой (и вы получите ее, даже если не укажете bound=Any для TypeVar , что, я согласен, бессмысленно). mypy-play.net/…

5. @AlexWaygood ну, вы получите совершенно другую ошибку, если удалите ее.

Ответ №1:

MyPy иногда может быть немного забавным в отношении типов классов. Вы можете решить эту проблему, указав _model как Callable[..., Item] (что, в конце концов, не является ложью) вместо Type[Item] :

 from abc import ABC
from typing import Generic, TypeVar, Any, ClassVar, Callable

Item = TypeVar("Item")


class SomeClass(Generic[Item], ABC):
    _model: ClassVar[Callable[..., Item]]

    def _compose_item(self, **attrs: Any) -> Item:
        return self._model(**attrs)