如果变量通过某些测试,则断言它具有某些属性

Asserting a variable has certain properties if it passes certain tests

使用 python 类型系统,我有时可以知道变量或表达式的类型,因为我已经安装了 运行时间检查来验证它。有没有办法用注释来表示这个?

例如,假设我有一个函数 combop,如果它的参数是 class Combination,它会 returns True。并进一步假设 class Combination 有一个名为 tds.

的字段
if combop(x):
   return f(x.tds)
else:
   return f([])

在此示例中,我想向检查器保证,在 if 的 then 部分中,x 的类型为 Combination,并且 x.tds 有意义。

这种情况的一个例子是 here python-rte 的第 172 行。 IDE 抱怨 d.tdsn.s。我假设有一种方法可以用类型注释来解释我的意图,并且 IDE 会在可能的情况下接受或验证我的主张。

在某些函数式语言(例如 Scala)中,这样做的方式是使用模式匹配。在模式匹配的子句中,类型推断器能够限制某些变量的类型。在其他一些语言(例如 Common Lisp)中,有一种 declare 语法,允许程序员向类型推断器提供提示,这可能会或可能不会贡献 运行 时间开销,具体取决于编译器设置。

import typing


class Foo:
    def __init__(self) -> None:
        self.bar = "zebra"  # will be of 'str' type


def give_me_something():  # no annotation here, can't tell what gets returned
    if dict():  # an empty dict is always False, this is just an example, a real condition could be used
        return []
    else:
        return Foo()


reveal_type(give_me_something())
reveal_type(typing.cast(Foo, give_me_something()))
$ mypy so69205255.py
so69205255.py:16: note: Revealed type is "Any"
so69205255.py:17: note: Revealed type is "so69205255.Foo"

我使用 MyPy 进行了可重复检查,但我的 IDE PyCharm 也理解它:当我将鼠标悬停在我分配表达式的变量名称时,它说第一个是类型 Union[list, Foo] 而第二个是 Foo.

类型

更多信息:参见 the docs

Python 3.10 将为 Python <= 3.9 引入新的 TypeGuard feature, which might provide you with what you're looking for. (The feature is also available through the typing_extensions 模块。) TypeGuard 允许您向类型检查器断言一个对象是某种类型的。因此,您可以编写如下函数:

from typing import TypeGuard, Any

def combop(obj: Any) -> TypeGuard[Combination]:
    # Some code that returns `True` if the object is of type `Combination`, else `False`.

如果您对对象的 属性 更感兴趣(“结构类型”而不是对象的“标称类型”),那么您可以使用a TypeGuard 断言您的对象符合某个 protocol.

from typing import Protocol, TypeGuard, Any

class CombinationsProto(Protocol):
    tds: list[Any]


def combops(obj: Any) -> TypeGuard[CombinationsProto]:
    # Some code here that returns `True` if the object has a `tds` attribute, else `False`.

由于这是 python 打字世界的一项新功能,Python 的主要类型检查器仍在努力支持此功能,特别是对于一些复杂的 corner cases.