如何键入提示其联合类型在 Python 中变窄的变量?

How can I type hint a variable whose Union type gets narrowed in Python?

我有一些辅助函数可以传递一个类型转换器和一个值。根据稍后发生的检查,我决定调用哪个辅助函数。

如何正确注释类型以缩小下面 foo 变量的类型,以便它可以通过 mypy 检查?

from typing import Type, Union


def do_something(
        typ: Type[Union[float, int]],
        bar: Union[float, int]
) -> Union[float, int]:
    return bar


foo: Type[Union[float, int, str]] = float

assert foo is float or foo is int

do_something(foo, 4.4)

如果解决方案可以确保 typbar 类型的转换器,则加分!

这里你想要的工具是TypeVar

本质上,一个 TypeVar 让你说“我不太清楚这是什么类型(虽然我可能有一些想法),但它在这个函数中的整个使用过程中都是相同的。” (或者在某些情况下,它在 class 中的整个使用过程中)

例如,这可确保您拥有 Union 的每个事物在对函数的任何给定调用中都获得相同的值。

from typing import Type, TypeVar

# Define a type variable
# and list the things it is allowed to represent
NumberType = TypeVar("NumberType", int, float) 

def do_something(
        typ: Type[NumberType],
        bar: NumberType
) -> NumberType:
    return bar

这可以合法地用 do_something(float, 2.5) 调用,在这种情况下它将 return 一个浮点数,或者它可以用 do_something(int, 2) 调用,在这种情况下它将 return一个整数。也就是说,它确保所有的东西都匹配。

因为您称它为类型转换器,我怀疑您实际上可能不希望所有类型都匹配。如果你需要约束多个类型变量,你可以使用更像

的东西来实现
from typing import Callable, TypeVar

# Define a type variable
# and list the things it is allowed to represent
NumberTypeIn = TypeVar("NumberTypeIn", int, float)
NumberTypeOut = TypeVar("NumberTypeOut", int, float) 

def do_something(
        converter: Callable[[NumberTypeIn], NumberTypeOut],
        bar: NumberTypeIn
) -> NumberTypeOut:
    return type_(bar)

关于缩小 Type[] 并集的原始问题,正如您所注意到的 is 不起作用。相反,您可以使用 issubclass,如

assert not issubclass(foo, str)

assert issubclass(foo, int) or issubclass(foo, float)