web-dev-qa-db-fra.com

Python typing que signifie TypeVar (A, B, covariant = True)?

Aujourd'hui, j'ai plongé en profondeur dans le principe de substitution de Liskov et la covariance/contravariance.

Et je suis resté coincé sur la différence entre:

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

Ma compréhension de # 1

Différence entre TypeVar ('T', A, B) et TypeVar ('T', bound = Union [A, B])

Cette réponse indique clairement que T peut être:

  1. Union[A, B] (Ou une union de tout sous-type de A et B tel que Union[A, BChild])
  2. A (ou tout sous-type de A)
  3. B (ou tout sous-type de B)

Cela me semble parfaitement logique.


Mon imparfait Compréhension de # 2

MyPy ne permet pas aux TypeVar contraints d'être covariants? Définition d'un dict générique avec des types clé-val contraints mais covariants

Re-mentionne le cas bound=Union[A, B], Mais n'obtient pas la signification de l'option # 2, A, B, covariant=True.

J'ai essayé de jouer avec mypy, et je n'arrive pas à le comprendre. Quelqu'un peut-il préciser ce que cela signifie?

I pense cela signifie:

  1. A (ou tout sous-type de A)
  2. B (ou tout sous-type de B)

(aka cela exclut le cas Union ci-dessus)


** Modifier **

Il a été demandé dans les commentaires:

Êtes-vous sûr qu'ils sont réellement différents?

Voici un exemple de code pour montrer la différence. Les erreurs proviennent de 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

** Modifier 2 **

J'ai fini par poser des questions à ce sujet dans python/mypy # 8806: Erreur générique [T_co] lorsque T_co = TypeVar ("T_co", A, B, covariant = True) et passé la sous-classe de A

Cela a dissipé certains malentendus que j'avais. Il s'avère que TypeVar("T", A, B, covariant=True) n'est pas vraiment correct, sachant que les restrictions de valeur A et B ne sont pas réellement covariantes.

L'utilisation de la syntaxe covariant=True N'est utile que lorsqu'elle est liée.

La covariance et la contra-variance sont des termes qui se rapportent à l'intersection entre l'orientation de l'objet et les génériques.

Voici la question à laquelle ce concept tente de répondre:

  1. Nous avons quelques classes "régulières", "orientées objet", Base et Derived.
  2. Nous avons également un type générique - disons List<T>.
  3. Nous savons que Derived peut être utilisé partout où la base le peut - cela signifie-t-il que List<Derived> peut être utilisé partout où List<Base> pouvez?
  4. Serait-ce l'inverse? C'est peut-être le sens inverse et maintenant List<Base> cab être utilisé partout où List<Derived> pouvez?

Si la réponse à (3) est oui, cela s'appelle la covariance et nous dirons déclarer List comme ayant covariance=True. Si la réponse à (4) est vraie, on l'appelle "contre-variance". Si aucun n'est vrai, c'est invariant.

Les limites proviennent également de l'intersection de OO et génériques. Lorsque nous définissons un type générique MyType - cela signifie-t-il que 'T' peut être n'importe quel type? Ou, puis-je imposer des limitations à ce que pourrait être T? Les limites me permettent de dire que la limite supérieure de T est, par exemple, la classe Derived. Dans ce cas, Base ne peut pas être utilisé avec 'MyType' - mais Derived et toutes ses sous-classes le peuvent.

La définition de la covariance et de la contravariance peut être trouvée dans cette section de PEP-484 .

3
Roy2012