【问题标题】:Python Typing with Exception Handling带有异常处理的 Python 类型
【发布时间】:2019-07-19 19:58:02
【问题描述】:

以下代码存储在一个名为 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() 可能返回没有groups 属性的None 类型,但会处理生成的异常并在返回类型中指定处理。但是,Mypy 似乎不明白正在处理异常。据我了解 Optional[Tuple[str, str]] 是正确的返回类型,而 Mypy 坚持认为不太具体的类型 Union[Sequence[str], Any] 是正确的。在 Python 类型中使用异常处理的正确方法是什么? (请注意,我并不是要求在不使用异常处理的情况下编写代码的替代方法。我只是想提供一个最小且完整的示例,其中 Python 类型检查器的行为与我对异常处理的预期不同。)

【问题讨论】:

    标签: python-3.x exception type-hinting mypy


    【解决方案1】:

    Mypy 并没有真正理解深层次的异常——在这种情况下,它不理解因为你正在捕获 AttributeError,它可以忽略“如果regex.match(path) 是 None 怎么办?”案例。

    更一般地说,mypy 所做的基本假设是,当您有一些对象 foo 类型为 Union[A, B] 并且您执行 foo.bar() 时,AB 类型都有一个 bar() 方法。

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

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

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

    同样,Mypy 也无法理解深层次的正则表达式——例如不会尝试分析您的正则表达式以确定您将获得多少组,因此不会理解您的特定正则表达式恰好与两个组匹配的字符串。它可以做的最好的事情是断言该组将返回一些未知数量的字符串——因此类型为Sequence[str] 而不是Tuple[str, str]

    这种限制在类型检查器中很常见,实际上:主流语言中的大多数类型系统并不真正支持根据传入的任何实际值的内容来判断返回类型的方法。这样的类型系统(依赖类型系统,细化类型系统......)很难实现,并且对于最终用户来说通常有一个陡峭的学习曲线。

    但是,如果您愿意的话,通过写mypy plugin 让mypy 更容易地在尽力 的基础上支持它。具体来说,请尝试查看get_method_hook()get_function_hook()

    【讨论】:

      猜你喜欢
      • 2018-11-15
      • 1970-01-01
      • 1970-01-01
      • 2017-11-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-02
      • 1970-01-01
      • 2012-12-22
      相关资源
      最近更新 更多