mypy 可以跟踪字符串文字吗?

Can mypy track string literals?

有没有办法让这个工作

from typing import Literal
def foo(bar: Literal["bar"]) -> Literal["foo"]:
    foo = "foo"
    return foo


bar = "bar"
foo(bar)

这里是错误

foo.py:4: error: Incompatible return value type (got "str", expected "Literal['foo']")
foo.py:8: error: Argument 1 to "foo" has incompatible type "str"; expected "Literal['bar']"

很明显 foo 变量和 bar 是文字,因为它们被分配给文字,所以这是安全的,但 mypy 似乎没有跟踪这一点。有什么我想念的吗?

MyPy 将文字推断为其内置类型,而不是其值的 Literal

mypy Docs » Literal types

You must explicitly add an annotation to a variable to declare that it has a literal type. [..] variables without this annotation are not assumed to be literals.

要允许推断 Literal 值,请将变量注释为 Final:

from typing import Final

from typing_extensions import Final

bar: Final = "bar"
reveal_type(bar)  # Revealed type is 'Literal['bar']?'

将变量注释为Final表示它的值不会被类似类型的值替代。这使得将类型推断为特定 Literal 值而不仅仅是一般类型是正确的。

请注意,此推断是上下文相关的:对于所有需要 Literal 的情况,类型都被推断为 Literal。对于预期类型的​​情况,无论是文字类型、基本类型还是 TypeVar,该类型都被推断为一般类型。

reveal_type([bar])  # Revealed type is 'builtins.list[builtins.str*]'