У меня есть сценарий python, и я пытаюсь добавить в код подсказки типов. Ниже приведен пример кода (без подсказок типа код работает) с использованием mypy.
values_int: list[int] = [1, 2, 3, 4]
values_str: list[str] = ["1", "2", "3", "4"]
def bar(*, x: list[int]) -> bool:
# processing
return True
def baz(*, y: list[str]) -> bool:
# processing
return True
def foo(*, values: list[int] | list[str]) -> bool:
status: bool = False
if isinstance(values[0], int):
x: list[int] = values
status = bar(x=x)
elif isinstance(values[0], str):
# case-1
# status = baz(y=values)
# case-2
y: list[str] = values
status = baz(y=y)
return status
foo(values=values_str)
Ошибки для:
# case-1
# error: Argument "y" to "baz" has incompatible type "list[int] | list[str]"; expected "list[str]"
# case-2
# error: Incompatible types in assignment (expression has type "list[int] | list[str]", variable has type "list[str]")
Я понимаю, что вы хотите, чтобы это значило именно это, но mypy хочет гарантий. (Думаю. В конце концов я удалил свой комментарий, по крайней мере, до тех пор, пока не смогу разобраться в этом самостоятельно.)
Подсказки по типам Синтаксис параметров типа PEP 695 поддерживаются в Python 3.12, но (пока) не поддерживаются в mypy.






isinstance(a[b], ...)(пока) не поддерживается как конструкция сужения типа. Как бы то ни было, Pyright также его не поддерживает.
Возможно, вам нужен индивидуальный TypeIs:
(playground links: Mypy , Pyright)
from typing_extensions import TypeIs
def is_list_of_ints(v: list[Any]) -> TypeIs[list[int]]:
return isinstance(v[0], int)
def is_list_of_strs(v: list[Any]) -> TypeIs[list[str]]:
return isinstance(v[0], int)
def foo(*, values: list[int] | list[str]) -> None:
reveal_type(values) # list[int] | list[str]
if is_list_of_ints(values):
reveal_type(values) # list[int]
bar(x=values) # fine
elif is_list_of_strs(values):
reveal_type(values) # list[str]
baz(y=values) # fine
Обратите внимание, что в Mypy 1.10.0 есть ошибка с TypeIs: она неправильно определяет вторую условную ветвь как недоступную:
def foo(*, values: list[int] | list[str]) -> None:
reveal_type(values) # list[int] | list[str]
if is_list_of_ints(values):
reveal_type(values) # list[int]
bar(x=values) # fine
elif is_list_of_strs(values):
reveal_type(values) # error: Statement is unreachable
baz(y=values)
Обходной путь — использовать TypeGuard:
from typing import TypeGuard
def is_list_of_ints(v: list[Any]) -> TypeGuard[list[int]]:
return isinstance(v[0], int)
def is_list_of_strs(v: list[Any]) -> TypeGuard[list[str]]:
return isinstance(v[0], int)
Разница между TypeIs и TypeGuard объясняется в PEP 742.
@tripleee, список всегда имеет один тип данных: либо все
int, либо всеstr