Я хочу ограничить возможные входные аргументы с помощью 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)
mypy в вашем случае верен: input_string
- это не литерал, а переменная типа str
. Попробуйте определить literal_func со строковым типом ввода.
К сожалению, 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
в переменную и передать ее дальше?
Я предполагаю, что в input_string = "best"
mypy выводит тип str
без дальнейшего сужения, поскольку позже переменная может быть изменена на другое значение str
. Таким образом, при прямом вызове с литералом literal_func("best")
можно «безопасно» сузить тип до литерала.
@Andi, когда вы делаете x = 'foo'
, для mypy
это по сути то же самое, что и декларация x: string
. mypy
не делает странных прыжков, таких как компилятор typescript или pyright, которые сначала пытаются вывести литеральный тип, а затем переопределяют его как строку только при переназначении - он просто говорит: «без явной аннотации, мы не можем знать, будет ли он повторно -назначается первым, а литералы достаточно редки, так что просто считайте это строкой". С модификатором Final
он точно знает, что переназначение запрещено, поэтому буквальный вывод безопасен. При прямом вызове вместо этого проверяется 'best' is compatible with 'best'
.
Выводимый тип
input_string
— это простоstr
, если вы не хотите встраивать его, вам придется явно указать более узкий тип, чтобы предотвратить переназначение значения, которое не является «лучшим» (или «худшим»).