python - TypeVar('T', A, B) 和 TypeVar('T', bound=Union[A, B]) 的区别
问题描述
我正在努力理解以下两个TypeVar
s 之间的区别:
from typing import TypeVar, Union
class A: pass
class B: pass
T = TypeVar("T", A, B)
T = TypeVar("T", bound=Union[A, B])
有人想开导我吗?
作为我不明白的一个例子:这通过了类型检查......
T = TypeVar("T", bound=Union[A, B])
class AA(A):
pass
class X(Generic[T]):
pass
class XA(X[A]):
pass
class XAA(X[AA]):
pass
...但是T = TypeVar("T", A, B)
,它失败了
错误:“X”的类型变量“T”的值不能是“AA”
相关:关于和之间区别的这个问题。Union[A, B]
TypeVar("T", A, B)
解决方案
当你这样做时T = TypeVar("T", bound=Union[A, B])
,你是在说 T 可以绑定到其中一个Union[A, B]
或任何子类型Union[A, B]
。它是联合的上限。
例如,如果你有一个 type 的函数def f(x: T) -> T
,那么传入以下任何类型的值都是合法的:
Union[A, B]
(或 A 和 B 的任何子类型的并集,例如Union[A, BChild]
)A
(或 A 的任何亚型)B
(或 B 的任何亚型)
这就是泛型在大多数编程语言中的行为方式:它们允许您强加一个上限。
但是当你这样做时T = TypeVar("T", A, B)
,你基本上是在说T
必须是 A 的上限或 B 的上限。也就是说,不是建立一个单一的上限,而是建立多个!
所以这意味着虽然传入类型A
或B
into的值是合法的f
,但传入是不合法的,Union[A, B]
因为联合既不是 A 也不是 B 的上限。
例如,假设您有一个可包含 int 或 strs 的可迭代对象。
如果您希望此可迭代对象包含任何整数或 strs 的任意混合,则只需要 a 的单个上限Union[int, str]
。例如:
from typing import TypeVar, Union, List, Iterable
mix1: List[Union[int, str]] = [1, "a", 3]
mix2: List[Union[int, str]] = [4, "x", "y"]
all_ints = [1, 2, 3]
all_strs = ["a", "b", "c"]
T1 = TypeVar('T1', bound=Union[int, str])
def concat1(x: Iterable[T1], y: Iterable[T1]) -> List[T1]:
out: List[T1] = []
out.extend(x)
out.extend(y)
return out
# Type checks
a1 = concat1(mix1, mix2)
# Also type checks (though your type checker may need a hint to deduce
# you really do want a union)
a2: List[Union[int, str]] = concat1(all_ints, all_strs)
# Also type checks
a3 = concat1(all_strs, all_strs)
相反,如果您想强制该函数接受所有 int或所有 str的列表,但绝不接受两者的混合,则需要多个上限。
T2 = TypeVar('T2', int, str)
def concat2(x: Iterable[T2], y: Iterable[T2]) -> List[T2]:
out: List[T2] = []
out.extend(x)
out.extend(y)
return out
# Does NOT type check
b1 = concat2(mix1, mix2)
# Also does NOT type check
b2 = concat2(all_ints, all_strs)
# But this type checks
b3 = concat2(all_ints, all_ints)
推荐阅读
- android - BroadcastReceiver - 无法从关闭或后台应用程序启动活动
- reactjs - 将 useEffect 与属性作为依赖项进行反应会导致无限循环
- angular - 升级全球 Angular cli 版本?
- javascript - 如何同时检测浏览器和移动设备?JavaScript
- python - 使用 Python Flask 的后续表单
- c# - C# worker 服务与 windows 服务
- r - R:读取缺少最后一列的 fwf 文件
- java - 在同一 TomEE 实例上的并行应用程序中使用 JasperReports 是不可能的(JasperReports 上下文)?
- c# - 自定义模型绑定器不会影响 ASP.NET CORE 3.1 中的属性
- javascript - 如何获取所选选项的索引