Python 使用异常处理进行键入
Python Typing with Exception Handling
以下代码存储在名为 sample.py.
的文件中
import re
from typing import Optional, Tuple
def func(path: str) -> Optional[Tuple[str, str]]:
regex = re.compile(r"/'([^/']+?)'/'([^/']+?)'")
try:
return regex.match(path).groups()
except AttributeError:
return None
Mypy Python linter 在分析代码时抛出以下错误:
sample.py:8: error: Incompatible return value type (got "Union[Sequence[str], Any]", expected "Optional[Tuple[str, str]]")
sample.py:8: error: Item "None" of "Optional[Match[str]]" has no attribute "groups"
虽然 regex.match(path).groups()
可能 return 一个没有 groups
属性的 None
类型,但会处理由此产生的异常并在 return类型。然而,Mypy 似乎不明白正在处理异常。据我了解 Optional[Tuple[str, str]]
是正确的 return 类型,而 Mypy 坚持认为不太具体的类型 Union[Sequence[str], Any]
是正确的。使用 Python 类型进行异常处理的正确方法是什么? (请注意,我并不是在寻求不使用异常处理的替代方法来编写代码。我只是想提供一个最小且完整的示例,其中 Python 类型检查器的行为与我预期的不同处理。)
Mypy 并不真正理解深层次的异常——在这种情况下,不理解因为你正在捕获 AttributeError,所以它可以忽略 "what if regex.match(path)
is None?" 案例。
更一般地说,mypy 所做的基本假设是,当您有一些类型为 Union[A, B]
的对象 foo
并且您做的是 foo.bar()
时,A
和 B
有一个 bar()
方法。
如果只有其中一种类型具有 bar()
方法,您需要执行以下操作之一:
- 在执行属性访问之前,请向 mypy 提供足够的信息以将联合缩小为相关类型之一。例如,isinstance 检查,
x is not None
检查...
- 确认您正在尝试做一些类型检查器不理解的事情,并满足于抑制生成的错误。例如,您可以转换类型,添加
# type: ignore
注释,找到使 foo
成为动态 Any
类型的方法...
- 找到一种重新设计代码的方法来解决 side-step 这个问题。
(在这种特殊情况下,我想另一种选择可能是向 mypy 提交拉取请求以添加对此模式的支持。但我不确定这是否真的可行:改变任何类型的基本假设都很困难在多个维度上工作。)
同样,Mypy 也不理解深层次的正则表达式——例如不会尝试分析您的正则表达式来确定您将获得多少组,因此不会理解您的特定正则表达式恰好与恰好两个组匹配的字符串。它能做的最好的事情就是断言该组将 return 一些未知数量的字符串——因此类型 Sequence[str]
而不是 Tuple[str, str]
.
这种限制在类型检查器中很常见,实际上:主流语言中的大多数类型系统并不真正支持根据任何实际值的内容来断言 return 类型的方法传入。此类类型系统(依赖类型系统、细化类型系统...)非常难以实现,并且对于最终用户而言通常具有陡峭的学习曲线。
但是, 可以更容易地让 mypy 在 best-effort 的基础上通过编写 [=26] 来支持它=],如果你愿意的话。具体来说,请尝试查看 get_method_hook()
和 get_function_hook()
.
以下代码存储在名为 sample.py.
的文件中import re
from typing import Optional, Tuple
def func(path: str) -> Optional[Tuple[str, str]]:
regex = re.compile(r"/'([^/']+?)'/'([^/']+?)'")
try:
return regex.match(path).groups()
except AttributeError:
return None
Mypy Python linter 在分析代码时抛出以下错误:
sample.py:8: error: Incompatible return value type (got "Union[Sequence[str], Any]", expected "Optional[Tuple[str, str]]")
sample.py:8: error: Item "None" of "Optional[Match[str]]" has no attribute "groups"
虽然 regex.match(path).groups()
可能 return 一个没有 groups
属性的 None
类型,但会处理由此产生的异常并在 return类型。然而,Mypy 似乎不明白正在处理异常。据我了解 Optional[Tuple[str, str]]
是正确的 return 类型,而 Mypy 坚持认为不太具体的类型 Union[Sequence[str], Any]
是正确的。使用 Python 类型进行异常处理的正确方法是什么? (请注意,我并不是在寻求不使用异常处理的替代方法来编写代码。我只是想提供一个最小且完整的示例,其中 Python 类型检查器的行为与我预期的不同处理。)
Mypy 并不真正理解深层次的异常——在这种情况下,不理解因为你正在捕获 AttributeError,所以它可以忽略 "what if regex.match(path)
is None?" 案例。
更一般地说,mypy 所做的基本假设是,当您有一些类型为 Union[A, B]
的对象 foo
并且您做的是 foo.bar()
时,A
和 B
有一个 bar()
方法。
如果只有其中一种类型具有 bar()
方法,您需要执行以下操作之一:
- 在执行属性访问之前,请向 mypy 提供足够的信息以将联合缩小为相关类型之一。例如,isinstance 检查,
x is not None
检查... - 确认您正在尝试做一些类型检查器不理解的事情,并满足于抑制生成的错误。例如,您可以转换类型,添加
# type: ignore
注释,找到使foo
成为动态Any
类型的方法... - 找到一种重新设计代码的方法来解决 side-step 这个问题。
(在这种特殊情况下,我想另一种选择可能是向 mypy 提交拉取请求以添加对此模式的支持。但我不确定这是否真的可行:改变任何类型的基本假设都很困难在多个维度上工作。)
同样,Mypy 也不理解深层次的正则表达式——例如不会尝试分析您的正则表达式来确定您将获得多少组,因此不会理解您的特定正则表达式恰好与恰好两个组匹配的字符串。它能做的最好的事情就是断言该组将 return 一些未知数量的字符串——因此类型 Sequence[str]
而不是 Tuple[str, str]
.
这种限制在类型检查器中很常见,实际上:主流语言中的大多数类型系统并不真正支持根据任何实际值的内容来断言 return 类型的方法传入。此类类型系统(依赖类型系统、细化类型系统...)非常难以实现,并且对于最终用户而言通常具有陡峭的学习曲线。
但是, 可以更容易地让 mypy 在 best-effort 的基础上通过编写 [=26] 来支持它=],如果你愿意的话。具体来说,请尝试查看 get_method_hook()
和 get_function_hook()
.