带有异常处理的Python输入

时间:2019-07-19 19:58:02

标签: python-3.x exception typing mypy

以下代码存储在名为 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()返回的None类型不具有groups属性,但是将处理所得的异常,并在返回类型中指定处理。但是,Mypy似乎不了解正在处理该异常。据我了解,Optional[Tuple[str, str]]是正确的返回类型,而Mypy坚持认为次要类型Union[Sequence[str], Any]是正确的。在Python类型中使用异常处理的正确方法是什么? (请注意,我不要求在不使用异常处理的情况下编写代码的替代方法。我只是试图提供一个最小而完整的示例,其中Python类型检查器的行为不如我期望的异常处理。) / p>

1 个答案:

答案 0 :(得分:1)

Mypy并没有真正深入地理解异常-在这种情况下,由于您正在捕获AttributeError,因此无法理解,它可以忽略“如果regex.match(path)为None怎么办?”情况。

更一般地说,mypy做出的基本假设是,当您拥有某个类型为foo的对象Union[A, B]并且执行了foo.bar()时,类型A和{{1 }}使用B方法。

如果这些类型中只有一种具有bar()方法,则需要执行以下操作之一:

  1. 在执行属性访问之前,给mypy提供足够的信息以将联合范围缩小为相关类型之一。例如,isinstance检查,bar()检查...
  2. 确认您正在尝试执行类型检查器无法理解的操作,并且无法抑制生成的错误。例如,您可以转换类型,添加x is not None注释,找到使# type: ignore成为动态foo类型的方法...
  3. 找到一种重新设计代码的方式来完全避开此问题。

(在这种特殊情况下,我想另一种选择可能是向mypy提交拉取请求,以添加对此模式的支持。但是我不确定这是否真的可行:更改任何基本假设都很难多个维度。)

同样,Mypy也无法深入了解正则表达式-例如不会尝试分析您的正则表达式来确定您将获得多少组,因此不会理解您的特定正则表达式恰好将字符串与两个组完全匹配。最好的办法是断言该组将返回一些未知数量的字符串-因此类型为Any而不是Sequence[str]

通常,这种限制在类型检查器中很常见,实际上:大多数主流语言的类型系统实际上并不支持基于传入的任何实际值的内容来确定返回类型的方法。此类类型系统(从属类型系统,优化类型系统...)很难实施,并且对于最终用户而言通常具有陡峭的学习曲线。

不过, 会更容易通过编写mypy plugin使尽力支持mypy。 。具体来说,尝试看看Tuple[str, str]get_method_hook()