python mypy不在函数定义中使用缩小的类型

f0brbegy  于 2022-11-21  发布在  Python
关注(0)|答案(1)|浏览(112)

我在mypy中遇到了一个问题。mypy没有在函数定义中使用缩小的类型。我有以下代码:

from typing import Callable

def foo(a: str | int) -> list[str]:
    x: list[str] = ["abc", "def"]
    if isinstance(a, int):
        x.insert(a, "ghi")
    elif isinstance(a, str):
        x.insert(0, a)
    return x

def bar(a: str | int) -> Callable[[list[str]], list[str]]:
    if isinstance(a, int):
        def modify(x: list[str]) -> list[str]:
            x.insert(a, "ghi")
            return x
    elif isinstance(a, str):
        def modify(x: list[str]) -> list[str]:
            x.insert(0, a)
            return x
    return modify

foo被正确地标识为良好类型。我相信bar也应该是良好类型的,但是mypy给出了以下错误:

16: error: Argument 1 to "insert" of "list" has incompatible type "Union[str, int]"; expected "SupportsIndex"
20: error: Argument 2 to "insert" of "list" has incompatible type "Union[str, int]"; expected "str"

这是mypy中的bug吗?有没有办法让我输入这个程序,否则?
与其他类型检查器相比,表明这是mypy特有的。Pyright在这里没有抱怨任何事情,但是如果x.insert(0, a)x.insert(a, "ghi")替换,则会抱怨。

pbpqsu0x

pbpqsu0x1#

我怀疑这是因为嵌套的函数定义使得名称解析和类型收缩变得非常复杂。您可以通过将a重新赋值给一个类型良好的变量,然后在每个分支中使用modify关闭该变量来解决这个问题:

from typing import Callable

def bar(a: str | int) -> Callable[[list[str]], list[str]]:
    if isinstance(a, int):
        # create a new variable with the correct type while mypy
        # can keep track of what's going on
        idx: int = a
        def modify(x: list[str]) -> list[str]:
            # close over the new variable instead of `a`
            x.insert(idx, "ghi")
            return x
    elif isinstance(a, str):
        # do the same thing here
        # the explicit type annotation isn't even actually necessary
        # I just put it for clarity
        s: str = a
        def modify(x: list[str]) -> list[str]:
            x.insert(0, s)
            return x
    return modify

相关问题