Python 中泛型函数的类型缩小

Type narrowing by a generic function in Python

提问人:pabouk - Ukraine stay strong 提问时间:7/22/2023 更新时间:7/22/2023 访问量:124

问:

我需要缩小类属性的类型。它被键入为,并且不应位于代码的特定部分中。我在生成器表达式中使用此属性,因此我不能直接使用带有条件或缩小条件的范围。MyType | NoneNoneraiseassert

下面的代码是定义泛型类型缩小函数的正确方法吗?即将参数定义为与泛型类型结合的泛型类型,但返回类型就像泛型类型一样。None

from typing import TypeVar

ValueT = TypeVar('ValueT')

def fail_if_none(value: ValueT | None) -> ValueT:
    """Raises an exception if the value is None.

    Args:
        value: The value to check.

    Raises:
        ValueError: If the value is None.

    Returns:
        The value, guaranteed to not be None.
    """
    if value is None:
        raise ValueError("Value cannot be None.")
    return value

代码是否保证返回类型将始终被视为不包括?难道没有更好的方法吗?ValueTNone


下面是一个示例,显示如何使用类型缩小函数:

def takes_int(value: int) -> int:
    """Take an int and return it."""
    return value

sequence: list[int | None] = [1, 2, 3, 4, None, 5]

values1 = (takes_int(value) for value in sequence)
# error: Argument 1 to "takes_int" has incompatible type "int | None";
# expected "int"  [arg-type]

values2 = (takes_int(fail_if_none(value)) for value in sequence)
# OK, no type-checker errors

我已经用 mypy 和 Pyright 测试了代码。在这两个类型检查器中,它似乎都按照我想要的方式工作。

python-3.x 泛型 python 类型缩小

评论

1赞 STerliakov 7/22/2023
是的,这对我来说似乎是一种正确且惯用的方式。你到底在问什么?如果一个东西可以正常工作并进行类型检查,您可能没有 StackOverflow 问题 - 请考虑在 Code Review SE 上提问。
0赞 pabouk - Ukraine stay strong 7/22/2023
@SUTerliakov支持罢工 问题是这是否是正确的方法。如果它在这种特定情况下有效,并不意味着它是正确的。最初,我根本不认为通过扩展论点可以行得通。ValueT| None
1赞 Daniil Fajnberg 7/23/2023
仅供参考,您可以在生成器表达式中使用条件。以下内容也将通过类型安全检查,尽管它当然不等价,因为这些值将被省略:None(takes_int(value) for value in sequence if value is not None)
1赞 pabouk - Ukraine stay strong 7/23/2023
@DaniilFajnberg谢谢。我知道这一点。我只是更喜欢通过不默默地跳过意外值来使程序更安全。

答: 暂无答案