Разница между TypeVar ('T', A, B) и TypeVar ('T', связанный = Union [A, B]) - PullRequest
2 голосов
/ 27 января 2020

Я изо всех сил пытаюсь осмыслить разницу между следующими двумя TypeVar с

from typing import TypeVar, Union

class A: pass
class B: pass

T = TypeVar("T", A, B)
T = TypeVar("T", bound=Union[A, B])

кто-нибудь хочет меня просветить?

Пример чего-то, чего я не делаю 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) происходит сбой при

generics.py: 31: ошибка: значение переменной типа "T" «X» не может быть «AA»

Относится к общему вопросу: этот вопрос о разнице между Union[A, B] и TypeVar("T", A, B)

1 Ответ

3 голосов
/ 27 января 2020

Когда вы делаете T = TypeVar("T", bound=Union[A, B]), вы говорите, что T может быть связан либо с Union[A, B], либо с любым подтипом Union[A, B]. Это верхний предел для объединения.

Так, например, если у вас есть функция типа def f(x: T) -> T, было бы допустимо передавать значения любого из следующих типов:

  1. Union[A, B] (или объединение любых подтипов A и B, таких как Union[A, BChild])
  2. A (или любой подтип A)
  3. 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...