如何进行类型注释类型断言?

How to make type-annotation-only type assertions?

我有两个功能:

def get_foo(params) -> Optional[str]
def bar(foo: str)

以及将这些函数链接在一起的函数:

def f(params):
    # other stuff up here
    foo = get_foo(params)
    return bar(foo)

根据函数中发生的其他事情,我知道 get_foo 的结果 永远不会 是 None。

当我运行mypy反对这个文件时,我当然会得到错误:

error: Argument 1 of "bar" has incompatible type "Optional[str]"; expected "str"

有道理。

我可以添加一个 assert foo is not None 语句,但这是热路径代码,在我的测试中它具有可衡量的性能影响。 我只想为 mypy 做一个类型断言。我该怎么做?

编辑:我也尝试在赋值语句后添加注释#type: str,但这产生了类似的错误

你不会对此感到高兴的。官方设计的向静态类型检查器断言值具有特定类型的方法是 typing.cast,这是一个具有实际 运行 时间成本的实际函数,我相信 more 比您要更换的 assert 贵。它只是 returns 它的第二个参数没有改变,但它仍然有函数调用开销。 Python 的类型注释系统不是用零开销类型断言语法设计的。

作为替代方案,您可以使用 Any 作为“逃生通道”。如果您使用类型 Any 注释 foo,mypy 应该允许 bar 调用。局部变量注释没有 运行 时间成本,因此唯一的 运行 时间成本是额外的局部变量存储和查找:

from typing import Any

def f(params):
    foo: Any = get_foo(params)
    return bar(foo)

除此之外,您最好的选择可能是使用 assert 和 运行 Python 以及 -O 标志,这会禁用断言。

您可以使用 TYPE_CHECKING 变量,该变量在运行时为 False,但在类型检查期间为 True。这将避免 assert:

的性能损失
from typing import TYPE_CHECKING

def f(params):
    # other stuff up here
    foo = get_foo(params)
    
    if TYPE_CHECKING:
        assert foo is not None
    
    return bar(foo)