Как я могу получить формат, чтобы не вызвать ошибку подсказки типа? - PullRequest
1 голос
/ 17 июня 2019

У меня есть следующие списки в Python:

from typing import cast

# everything is fine
print([value for value in [1, 2, 3, 4]])

# on the first "value": Expression type contains "Any" (has type "List[Any]")
print("{}".format([value for value in [1, 2, 3, 4]]))

# on the "cast": Expression type contains "Any" (has type "List[Any]")
print("{}".format([cast(int, value) for value in [1, 2, 3, 4]]))

Почему использование format приводит к тому, что Mypy возвращает мне ошибки?Как вы можете видеть, я пытался использовать приведение, но оно все равно не удалось.

Этот вопрос выглядит аналогично, но мой конкретный случай странный, потому что с Mypy все в порядке, пока яне использовать функцию format (но с функцией print все в порядке).

Что я могу сделать, чтобы строки с форматированием не вызывали ошибок?(Или я должен просто # type: ignore их?)

РЕДАКТИРОВАТЬ: Обратите внимание, что это не просто проблема с моим линтом Atom.Я использую версию Mypy 0.701, и я запустил Mypy для файла со следующим результатом:

$ python3 -m mypy testing_list_iter.py --disallow-any-expr
testing_list_iter.py:7: error: Expression type contains "Any" (has type "List[Any]")
testing_list_iter.py:10: error: Expression type contains "Any" (has type "List[Any]")

1 Ответ

4 голосов
/ 17 июня 2019

Это на самом деле не имеет ничего общего со списком: это на самом деле плохое взаимодействие между сигнатурой типа для 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.

...