Python печатать что значит TypeVar (A, B, covariant = True)? - PullRequest
9 голосов
/ 03 мая 2020

Сегодня я глубоко погрузился в Принцип замещения Лискова и ковариацию / контравариантность.

И застрял на разнице между:

  1. T = TypeVar("T", bound=Union[A, B])
  2. T = TypeVar("T", A, B, covariant=True)

Мое понимание # 1

Разница между TypeVar ('T', A, B) и TypeVar ('T', связанный = Союз [A, B])

Этот ответ четко гласит T может быть:

  1. Union[A, B] (или объединение любых подтипов A и B, таких как Union[A, BChild])
  2. A (или любой подтип A)
  3. B (или любой подтип B)

Это имеет для меня смысл.


Мой Недостатки Понимание # 2

MyPy не позволяет ограниченным TypeVar быть ковариантными? Определение обобщенного c dict с ограниченным, но ковариантным типом key-val

Повторно упоминает случай bound=Union[A, B], но не понимает значение опции # 2, A, B, covariant=True.

Я попытался поиграться с mypy, и не могу понять это. Кто-нибудь может указать, что это значит?

Я думаю это означает:

  1. A (или любой подтип A)
  2. B (или любой подтип B)

(он также исключает случай Union сверху)


** Редактировать **

В комментариях спросили:

Вы уверены, что они на самом деле разные?

Вот пример кода, чтобы показать разницу. Ошибки происходят от mypy==0.770.

from typing import Union, TypeVar, Generic


class A: pass

class ASub(A): pass

class B: pass


# Case 1... Success: no issues found
# T = TypeVar("T", bound=Union[A, B])

# Case 2... error: Value of type variable "T" of "SomeGeneric" cannot be "ASub"
T = TypeVar("T", A, B, covariant=True)


class SomeGeneric(Generic[T]): pass

class SomeGenericASub(SomeGeneric[ASub]): pass

1 Ответ

2 голосов
/ 11 мая 2020

Ковариация и контр-дисперсия - это термины, которые относятся к пересечению между ориентацией объекта и дженериками.

Вот вопрос, на который пытается ответить эта концепция:

  1. У нас есть пара «обычных», «объектно-ориентированных» классов, Base и Derived.
  2. У нас также есть некоторый обобщенный тип c - скажем, List<T>.
  3. Мы знаем, что Derived можно использовать везде, где может база - это означает, что List<Derived> можно использовать везде, где List<Base> может?
  4. Может ли быть наоборот? Может быть, это обратное направление, и теперь кабина List<Base> может использоваться везде, где может List<Derived>?

Если ответ на (3) положительный, это называется ковариацией, и мы скажем объявить List как имеющее covariance=True. Если ответ на (4) верен, он называется «контр-дисперсия». Если ничего не верно, это инвариант.

Границы также приходят от пересечения ОО и дженериков. Когда мы определяем универсальный тип c MyType - означает ли это, что 'T' может быть любым типом вообще? Или я могу наложить некоторые ограничения на то, что Т может быть? Границы позволяют мне утверждать, что верхней границей T является, например, класс Derived. В этом случае Base нельзя использовать с MyType, но можно Derived и все его подклассы.

Определение ковариации и контравариантности можно найти в этом разделе PEP-484 .

...