Это на самом деле не имеет ничего общего со списком: это на самом деле плохое взаимодействие между сигнатурой типа для str.format(...)
, тем, как mypy выполняет вывод типа, и флагом --disallow-any-expr
.
Вот сигнатура типа для str.format(...)
, , извлеченного из типизированного :
def format(self, *args: Any, **kwargs: Any) -> str: ...
Когда mypy выполняет вывод типов при вызовах функций, он пытается использовать объявленные типы параметров, чтобы помочь обеспечить контекст для выражений, которые вы передаете.
Таким образом, в этом случае, поскольку все аргументы Any
здесь, mypy поймет, что он может сокращать многие типы вывода, которые обычно необходимы для выполнения. Таким образом, если мы передадим какой-либо литерал списка в str.format(...)
, mypy просто примет решение «эй, выводимый тип может быть просто List[Any]
».
Вот пример программы, которая демонстрирует это поведение (при проверке с флагом --disallow-any-expr
):
from typing import cast, Any
def test1(x: Any) -> None:
pass
def test2(x: object) -> None:
pass
# Revealed type is 'builtins.list[Any]'
# Expression type contains "Any" (has type "List[Any]")
test1(reveal_type([1, 2, 3, 4]))
# Revealed type is 'builtins.list[builtins.int*]'
test2(reveal_type([1, 2, 3, 4]))
Обратите внимание, что когда мы пытаемся использовать функцию, которая принимает object
вместо Any
, mypy выведет полный тип вместо этого ярлыка. (Технически Mypy мог бы сделать тот же самый вид ярлыка, поскольку все типы также являются подклассами object
, но я подозреваю, что с точки зрения реализации это было просто проще - в отличие от Any
, object
- это обычный обычный старый тип так что взаимодействие в специальном корпусе довольно странно.)
Как правило, неважно, насколько точно mypy обрабатывает этот случай: вы получите точные результаты в любом случае.
Тем не менее, флаг --disallow-any-expr
все еще довольно новый и относительно непроверенный (он слишком агрессивен для многих людей, особенно для тех, кто пытается использовать mypy в существующих кодовых базах), поэтому мы время от времени получаем эти плохие взаимодействия .
Так в чем же дело?
Наилучшим из возможных исправлений было бы то, чтобы вы отправили запрос на извлечение в Typeshed, изменив str.format(...)
и unicode.format(...)
в файле builtins.pyi , чтобы они принимали объекты вместо Any
.
Это изменение будет в любом случае соответствовать рекомендациям Typeshed в любом случае - в частности, этот фрагмент в середине раздела "Условные обозначения":
При добавлении подсказок к типу, по возможности, избегайте использования типа Any
. Зарезервируйте использование Any
для случаев, когда:
- правильный тип не может быть выражен в текущей системе типов; и
- , чтобы избежать возврата Союза (см. Выше).
Обратите внимание, что Any
не является правильным типом для использования, если вы хотите указать, что какая-то функция может принимать буквально что угодно: в этих случаях используйте object
вместо.
Затем вы ждете следующего выпуска mypy, который теоретически должен быть в скором времени.
Тем временем вы можете просто присвоить результаты вашего понимания списка новой переменной, а затем передать , что , в str.format(...)
:
results = [value for value in [1, 2, 3, 4]]
print("{}".format(results))
Это заставит mypy выводить тип вашего списка понимания без контекста Any
, заставляя его выводить полноценный тип. Это позволяет избежать плохого взаимодействия с флагом --disallow-any-expr
.