如何创建一个以类似于
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 通常只理解几种缩小类型的特定方法,例如使用
isinstance
或 if x is not None
。然而,在 Python >=3.10 中,PEP 647 通过新的 typing.TypeGuard
功能提供了此问题的解决方案。现在,您可以像这样编写 ComplexTypeAssertion
函数,并且类型检查器将理解,如果函数返回 data
,则 list[str]
保证为 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
也可用于 PyPI<3.10 via the semi-official 上的 Python typing-extensions
库,它提供了较新类型构造到早期版本 Python 的反向移植。 (如果您使用 Mypy,您会发现 typing-extensions
已经是 Mypy 的依赖项,因此从 typing-extensions
导入某些内容甚至不一定意味着您必须向项目添加额外的依赖项。)