У меня есть следующий аннотированный тип Django код:
from typing import Optional, Type, TypeVar
from django.db import models
T = TypeVar('T', bound=models.Model)
def get_obj_or_none(model: Type[T], obj_id: int) -> Optional[T]:
try:
return model.objects.get(pk=obj_id)
except model.DoesNotExist:
return None
Функция ожидает класс, полученный из django.db.models.Model
в качестве первого параметра и int
id в качестве второго параметра:
# obj is now the Person with id 123, or None if that didn't exist.
obj = get_obj_or_none(Person, 123)
Но когда я запускаю mypy в коде, я получаю сообщение об ошибке:
error: "Type[T]" has no attribute "objects"
error: "Type[T]" has no attribute "DoesNotExist"
Но если изменить код на этот и снова запустить mypy, я не получите ошибок:
from typing import Optional, Type
from django.db import models
def get_obj_or_none(model: Type[models.Model], obj_id: int) -> Optional[models.Model]:
try:
return model.objects.get(pk=obj_id)
except model.DoesNotExist:
return None
Почему не работает первый пример? Я действительно предпочел бы использовать его, так как второй пример никак не возвращает ie возвращаемое значение параметру model
, поэтому функция может возвращать экземпляр, который полностью не связан с классом, заданным как первый параметр.
Я использую Python 3.8.1 с mypy 0,761.
Редактировать :
Вот самодостаточный Пример, который можно проверить следующим образом:
from typing import Dict, Optional, Type, TypeVar
class Model:
objects: Dict[int, 'Model'] = {}
T = TypeVar('T', bound=Model)
def get_obj_or_none(model: Type[T], obj_id: int) -> Optional[T]:
try:
return model.objects[obj_id]
except KeyError:
return None
Запуск mypy на этом дает (к моему удивлению) совершенно другую ошибку:
type_example.py:17: error: Incompatible return value type (got "Model", expected "Optional[T]")
Found 1 error in 1 file (checked 1 source file)
Почему mypy ведут себя по-разному на этих двух примерах? Можно ли как-то исправить оба случая?