TypeVar('T',A,B)和TypeVar('T',bound = Union [A,B])之间的区别 [英] Difference between TypeVar('T', A, B) and TypeVar('T', bound=Union[A, B])
问题描述
我正在努力理解以下两个TypeVar
s
I'm struggling to get my head around the difference between the following two 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])
有人想启发我吗?
一个我不明白的例子...
An example of something I don't get ...
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)
失败,
passes type checking, but with T = TypeVar("T", A, B)
it fails with
generics.py:31:错误:"X"类型变量"T"的值不能为"AA"
generics.py:31: error: Value of type variable "T" of "X" cannot be "AA"
与一般问题有关:此问题有关Union[A, B]
和TypeVar("T", A, B)
Related to the general question: this question on the difference between Union[A, B]
and TypeVar("T", A, B)
推荐答案
执行T = TypeVar("T", bound=Union[A, B])
时,是说T可以绑定到Union[A, B]
或Union[A, B]
的任何子类型. 边界上限.
When you do T = TypeVar("T", bound=Union[A, B])
, you are saying T can be bound to either Union[A, B]
or any subtype of Union[A, B]
. It's upper-bounded to the union.
因此,例如,如果您具有类型为def f(x: T) -> T
的函数,则传入以下任何类型的值都是合法的:
So for example, if you had a function of type def f(x: T) -> T
, it would be legal to pass in values of any of the following types:
-
Union[A, B]
(或A和B的任何子类型的并集,例如Union[A, BChild]
) -
A
(或A的任何子类型) -
B
(或B的任何子类型)
Union[A, B]
(or a union of any subtypes of A and B such asUnion[A, BChild]
)A
(or any subtype of A)B
(or any subtype of B)
这是大多数编程语言中泛型的行为方式:它们使您可以施加一个上限.
This is how generics behave in most programming languages: they let you impose a single upper bound.
但是,当您执行T = TypeVar("T", A, B)
时,您基本上是说T
必须要么是A的上限,要么是B的上限.也就是说,不是建立一个上限,您就可以建立多个!
But when you do T = TypeVar("T", A, B)
, you are basically saying T
must be either upper-bounded by A or upper-bounded by B. That is, instead of establishing a single upper-bound, you get to establish multiple!
因此,这意味着将A
或B
类型的值传递到f
是合法的,但由于Union[A, B]
联盟的上限既不是A也不是B.
So this means while it would be legal to pass in values of either types A
or B
into f
, it would not be legal to pass in Union[A, B]
since the union is neither upper-bounded by A nor B.
例如,假设您有一个可包含int或strs的可迭代对象.
So for example, suppose you had a iterable that could contain either ints or strs.
如果您希望此可迭代项包含int或str的任意混合,则只需一个Union[int, str]
的单个上限.例如:
If you want this iterable to contain any arbitrary mixture of ints or strs, you only need a single upper-bound of a Union[int, str]
. For example:
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)
相反,如果要强制执行该函数将接受 all ints 或 all strs 的列表,但不接受两者的混合,则需要多个上限.
In contrast, if you want to enforce that the function will accept either a list of all ints or all strs but never a mixture of either, you'll need multiple upper bounds.
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)
这篇关于TypeVar('T',A,B)和TypeVar('T',bound = Union [A,B])之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!