Подсказки типа Python: как использовать Literal со строками, чтобы соответствовать mypy?

Я хочу ограничить возможные входные аргументы с помощью typing.Literal.

Следующий код работает нормально, однако mypy жалуется.

from typing import Literal


def literal_func(string_input: Literal["best", "worst"]) -> int:
    if string_input == "best":
        return 1
    elif string_input == "worst":
        return 0


literal_func(string_input = "best")  # works just fine with mypy

# The following call leads to an error with mypy:
# error: Argument "string_input" to "literal_func" has incompatible type "str";
# expected "Literal['best', 'worst']"  [arg-type]

input_string = "best"
literal_func(string_input=input_string)

Выводимый тип input_string — это просто str, если вы не хотите встраивать его, вам придется явно указать более узкий тип, чтобы предотвратить переназначение значения, которое не является «лучшим» (или «худшим»).

jonrsharpe 24.11.2022 09:30

mypy в вашем случае верен: input_string - это не литерал, а переменная типа str. Попробуйте определить literal_func со строковым типом ввода.

Sandwichnick 24.11.2022 09:35
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
361
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

К сожалению, mypy не сужает тип input_string до Literal["best"]. Вы можете помочь ему с правильной аннотацией типа:

input_string: Literal["best"] = "best"
literal_func(string_input=input_string)

Возможно, стоит упомянуть, что pyright отлично работает с вашим примером.


Кроме того, того же можно добиться, аннотировав input_string как Final:

from typing import Final, Literal

...

input_string: Final = "best"
literal_func(string_input=input_string)

Ваш ответ правильный. Однако я не понимаю, почему mypy не жалуется, когда я напрямую отправляю str, как в literal_func("best")? В чем разница в том, чтобы поместить это str в переменную и передать ее дальше?

Andi 24.11.2022 09:43

Я предполагаю, что в input_string = "best" mypy выводит тип str без дальнейшего сужения, поскольку позже переменная может быть изменена на другое значение str. Таким образом, при прямом вызове с литералом literal_func("best") можно «безопасно» сузить тип до литерала.

Paweł Rubin 24.11.2022 09:46

@Andi, когда вы делаете x = 'foo', для mypy это по сути то же самое, что и декларация x: string. mypy не делает странных прыжков, таких как компилятор typescript или pyright, которые сначала пытаются вывести литеральный тип, а затем переопределяют его как строку только при переназначении - он просто говорит: «без явной аннотации, мы не можем знать, будет ли он повторно -назначается первым, а литералы достаточно редки, так что просто считайте это строкой". С модификатором Final он точно знает, что переназначение запрещено, поэтому буквальный вывод безопасен. При прямом вызове вместо этого проверяется 'best' is compatible with 'best'.

SUTerliakov 24.11.2022 14:26

Другие вопросы по теме