На самом деле это не имеет ничего общего с пониманием списка: на самом деле это плохое взаимодействие между сигнатурой типа для str.format(...)
, тем, как mypy выполняет вывод типа, и флагом --disallow-any-expr
.
Вот подпись типа для str.format(...)
, вытащенная из typeshed а>:
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
.
person
Michael0x2a
schedule
17.06.2019
[1, 2, 3, 4]
вывода) - person Pro Q   schedule 17.06.2019