我可以通知 mypy 表达式不会 return 可选吗?

Can I inform mypy that an expression will not return an Optional?

我有以下代码:

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

mypy 在最后一行抛出错误:

Item "None" of "Optional[Match[str]]" has no attribute "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("-", "")

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

Incompatible types in assignment (expression has type "Optional[Match[Any]]", variable has type "Match[Any]")

我真的不知道如何通知 mypy 结果不是可选的,但我还是按照 Optional types and the None type 的建议添加了一个断言:

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("-", "")

但是 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("-", "")

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

Item "None" of "Optional[Match[Any]]" has no attribute "group"

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

Optionalevent_date,因为 re.search 不能保证 return 匹配。 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("-", "")

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

请注意,无需对 bucket_path 断言,因为它已明确键入为 str

另一种可能性是使用 isinstance.

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

在这里你会 return "" 而不是 None.