Когда вы делаете T = TypeVar("T", bound=Union[A, B])
, вы говорите, что T может быть связан либо с Union[A, B]
, либо с любым подтипом Union[A, B]
. Это верхний предел для объединения.
Так, например, если у вас есть функция типа 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. То есть вместо установления single upper- ограниченный, вы можете установить sh кратно!
Таким образом, это означает, что, хотя было бы законно передавать значения любого типа A
или B
в f
, не допустимо передавать в Union[A, B]
, так как объединение не ограничено ни A, ни верхним пределом.
Так, например, предположим, что у вас была итерация, которая могла бы c Укажите либо ints, либо strs.
Если вы хотите, чтобы эта итерация содержала любую произвольную смесь int или strs, вам нужна только одна верхняя граница 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)
Напротив, если вы хотите, чтобы функция принимала либо список всех целых , либо всех строковых , но никогда не смесь либо вам понадобится несколько верхних границ.
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)