受约束的 TypeVar 和 Union 有什么区别?
What's the difference between a constrained TypeVar and a Union?
如果我想要一个可以是多种可能类型的类型,Union
s 似乎是我的表示方式:
U = Union[int, str]
U
可以是 int
或 str
.
我注意到 TypeVar
s 允许可选的 var-arg 参数似乎也做同样的事情:
T = TypeVar("T", int, str)
T
和 U
似乎都只允许采用 str
和 int
.
类型
这两种方式有什么区别,什么时候应该首选它们?
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 + int
和 str + str
可以,但 int + str
和 str + 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 * str
和 str * 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 + int
或str + str
:
from typing import TypeVar
T = TypeVar("T", int, str)
def add(a: T, b: T) -> T:
return a + b
如果我想要一个可以是多种可能类型的类型,Union
s 似乎是我的表示方式:
U = Union[int, str]
U
可以是 int
或 str
.
我注意到 TypeVar
s 允许可选的 var-arg 参数似乎也做同样的事情:
T = TypeVar("T", int, str)
T
和 U
似乎都只允许采用 str
和 int
.
这两种方式有什么区别,什么时候应该首选它们?
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 + int
和 str + str
可以,但 int + str
和 str + 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 * str
和 str * 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 + int
或str + str
:
from typing import TypeVar
T = TypeVar("T", int, str)
def add(a: T, b: T) -> T:
return a + b