如何在 Python 中创建用户定义的类型断言?

How to create a user-defined type assertion in Python?

如何创建一个以类似于 isinstance 的方式缩小变量类型(对于静态类型检查器)的函数?

例如,ComplexTypeAssertion 只是在运行时缩小类型,而不是用于静态检查:

def MyFunction(myData: object) -> object:
  if isinstance(myData, list):
    reveal_type(myData)  # Revealed type is 'builtins.list[Any]'
  if ComplexTypeAssertion(myData):   # <<< How to make MyPy understand this?
    reveal_type(myData)  # Revealed type is 'builtins.object'

def ComplexTypeAssertion(data: object) -> bool:
    return isinstance(data, list) and all(isinstance(value, str) for value in data)

如何定义 ComplexTypeAssertion 以便静态分析工具能够理解类型?

显然,这是一个玩具示例,现实生活中的示例会更复杂。在我想断言某些数据遵循 TypedDict 构造或其他类型构造的情况下,这将非常有用。

Mypy 通常只理解几种缩小类型的特定方法,例如使用 isinstanceif x is not None。但是,在 Python >=3.10 中,PEP 647 通过新的 typing.TypeGuard 功能提供了解决此问题的方法。现在,您可以像这样编写 ComplexTypeAssertion 函数,类型检查器将理解 data 保证是 list[str] 类型,如果函数 returns True:

from typing import TypeGuard

def ComplexTypeAssertion(data: object) -> TypeGuard[list[str]]:
    return isinstance(data, list) and all(isinstance(value, str) for value in data)

TypeGuard 也可通过半官方 typing-extensions library on PyPI 用于 Python <3.10,它为 Python 的早期版本提供了较新类型结构的反向移植。 (如果你正在使用 Mypy,你会发现 typing-extensions 已经是 Mypy 的依赖项,所以从 typing-extensions 导入一些东西甚至不一定意味着你必须添加额外的依赖项到你的项目。)