受约束的 TypeVar 和 Union 有什么区别?

What's the difference between a constrained TypeVar and a Union?

如果我想要一个可以是多种可能类型的类型,Unions 似乎是我的表示方式:

U = Union[int, str] 

U 可以是 intstr.

我注意到 TypeVars 允许可选的 var-arg 参数似乎也做同样的事情:

T = TypeVar("T", int, str)

TU 似乎都只允许采用 strint.

类型

这两种方式有什么区别,什么时候应该首选它们?

T 的类型必须在给定的 scope 中的多次使用中保持一致,而 U 则不然。

使用 Union 类型作为函数参数,参数和 return 类型都可以不同:

U = Union[int, str]

def union_f(arg1: U, arg2: U) -> U:
    return arg1

x = union_f(1, "b")  # No error due to different types
x = union_f(1, 2)  # Also no error
x = union_f("a", 2)  # Also no error
x # And it can't tell in any of the cases if 'x' is an int or string

将其与具有 TypeVar 的类似情况进行比较,其中参数类型必须匹配:

T = TypeVar("T", int, str)

def typevar_f(arg1: T, arg2: T) -> T:
    return arg1

y = typevar_f(1, "b")  # "Expected type 'int' (matched generic type 'T'), got 'str' instead
y = typevar_f("a", 2)  # "Expected type 'str' (matched generic type 'T'), got 'int' instead

y = typevar_f("a", "b")  # No error
y  # It knows that 'y' is a string

y = typevar_f(1, 2)  # No error
y  # It knows that 'y' is an int

因此,如果允许多种类型,请使用 TypeVar,但在单个范围内 T 的不同用法必须相互匹配。如果允许多种类型,则使用 Union,但给定范围内 U 的不同用法不需要​​相互匹配。

由于@Carcigenicate 的解释,我想补充一点:

对于 Union,您在参数之间使用的操作必须由所有参数支持 以任何排列顺序:

from typing import Union

U = Union[int, str]

def add(a: U, b: U):
    return a + b

这里 int + intstr + str 可以,但 int + strstr + int 不行。
Mypy 说:

main.py:6: error: Unsupported operand types for + ("int" and "str")
main.py:6: error: Unsupported operand types for + ("str" and "int")

如果我们将 + 更改为 *int * strstr * int 以及 int * int 可以,但 Mypy 不喜欢 str * str :

from typing import Union

U = Union[int, str]

def add(a: U, b: U):
    return a * b

Mypy 说:

main.py:6: error: Unsupported operand types for * ("str" and "str")

如果我们通过上述测试将 U = Union[int, str] 更改为 U = Union[int, float],它会接受。四种情况都可以接受。

这里我们使用TypeVar代替那些抱怨,T是一样的,int + intstr + str:

from typing import TypeVar

T = TypeVar("T", int, str)

def add(a: T, b: T) -> T:
    return a + b