我可以告诉 mypy 表达式不会返回可选值吗?

jam*_*iet 12 python mypy python-typing

我有以下代码:

def extract_table_date(bucket_path: str) -> str:
    event_date = re.search(r"date=([^/]+)", bucket_path)
    return event_date.group(1)[0:10].replace("-", "")
Run Code Online (Sandbox Code Playgroud)

mypy 在最后一行抛出错误:

“Optional[Match[str]]”的“None”项没有属性“group”

我想我可以通过为 分配一个类型来解决这个问题event_date,我可以:

from typing import Match

def extract_table_date(bucket_path: str) -> str:
    event_date: Match = re.search(r"date=([^/]+)", bucket_path)
    return event_date.group(1)[0:10].replace("-", "")
Run Code Online (Sandbox Code Playgroud)

但 mypy 现在在函数的第一行抛出另一个错误:

赋值中的类型不兼容(表达式的类型为“Optional[Match[Any]]”,变量的类型为“Match[Any]”)

我真的不知道如何通知 mypy 结果不是可选的,但尽管如此,我还是遵循了可选类型和 None 类型的建议,添加了断言:

from typing import Match

def extract_table_date(bucket_path: str) -> str:
    assert bucket_path is not None
    event_date: Match = re.search(r"date=([^/]+)", bucket_path)
    return event_date.group(1)[0:10].replace("-", "")
Run Code Online (Sandbox Code Playgroud)

但 mypy 仍然引发相同的错误。

我尝试通过更改定义的类型来修复event_date

from typing import Match, optional, Any

def extract_table_date(bucket_path: str) -> str:
    assert bucket_path is not None
    event_date: Optional[Match[Any]] = re.search(r"date=([^/]+)", bucket_path)
    return event_date.group(1)[0:10].replace("-", "")
Run Code Online (Sandbox Code Playgroud)

但是(正如预期的那样)我现在又回到了几乎相同的原始错误:

“可选[匹配[任意]]”的项目“无”没有属性“组”

关于如何解决这个问题有什么建议吗?

Sam*_*ord 20

问题是Optional,event_date因为re.search不能保证返回匹配项。mypy 警告您,如果AttributeError是这种情况,这将引发一个错误。assert您可以通过执行以下操作来告诉它“不,我非常有信心不会出现这种情况” :

def extract_table_date(bucket_path: str) -> str:
    event_date = re.search(r"date=([^/]+)", bucket_path)
    assert event_date is not None
    return event_date.group(1)[0:10].replace("-", "")
Run Code Online (Sandbox Code Playgroud)

如果你错了,这段代码仍然会引发异常(AssertionError,因为你会失败),但 mypy 将不再出错,因为现在当你访问它的属性时assert没有办法event_date出错。Nonegroup

请注意,无需断言 on,bucket_path因为它已经显式键入为str

  • 然后你必须将返回值输入为“Optional[str]”,这可能不是你想要的。当需要 `str` 时返回 `None` 可能会导致堆栈中更高位置的另一个异常 - 如果您有编程错误,最好是快速而响亮地失败,而不是缓慢和/或默默地失败,因为它会给您带来好处调试时更有用的堆栈跟踪。:) (6认同)
  • 如果字符串没有预期的内容,那么对于其他人正在使用的 API,这里要做的“正确”的事情可能会引发特定的异常(我可能会使用“ValueError”),并记录接口为“返回str,如果bucket_path中没有日期则引发ValueError”。(这类似于 `int("foo")` 引发 ValueError 的方式,因为其参数的值不是有效的数字。)但是对于您不太担心拥有超级干净的 API 的私有函数,`assert ` 既快速又简单,因为它用一行代码完成了几乎相同的事情。 (2认同)