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:
T = TypeVar("T", bound=Union[A, B])
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:
Union[A, B]
(Ou une union de tout sous-type deA
etB
tel queUnion[A, BChild]
)A
(ou tout sous-type deA
)B
(ou tout sous-type deB
)
Cela me semble parfaitement logique.
Mon imparfait Compréhension de # 2
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:
A
(ou tout sous-type de A
)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:
Base
et Derived
.List<T>
.List<Derived>
peut être utilisé partout où List<Base>
pouvez?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 .