给定 list[int] | 的参数list[str],如果元素[0]是int,我不能确定列表是list[int],反之亦然吗?

问题描述 投票:0回答:2

我有一个

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]")
python mypy
2个回答
0
投票

MyPy 似乎会要求您显式检查列表中的所有元素是否都是预期类型。我尝试了各种方法,但这只给我带来了新的错误,但这个简单的方法有效:

def foo(*, values: list[int] | list[str]) -> bool:
    status: bool = False

    first = type(values[0])
    for x in values[1:]:
        if not isinstance(x, first):
            raise ValueError(f"All values must be of type {first}")

    if first is int:
        status = bar(x=values_int)
    else:
        status = baz(y=values_str)

    return status

0
投票

isinstance(a[b], ...)
不支持 作为类型缩小结构。 无论如何,Pyright 也不支持它。

也许您想要定制的

TypeIs

(游乐场链接:MypyPyright

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)
© www.soinside.com 2019 - 2024. All rights reserved.