Je suis en train de mettre en place une interface pour les conversions entre les types, mais j'ai du mal à la rendre cohérente car typing.Type
est covariant
U = TypeVar('U')
class Into(Protocol[U]):
@abstractmethod
def into(self, t: Type[U]) -> U:
pass
La documentation donne un exemple similaire avec une différence cruciale
class Utilisateur: ...
class UtilisateurBasique(Utilisateur): ...
class UtilisateurPro(Utilisateur): ...
class UtilisateurEquipe(Utilisateur): ...
def creer_nouvel_utilisateur(classe_utilisateur: Type[Utilisateur]) -> Utilisateur:
return classe_utilisateur()
Là, ils disent que les vérificateurs de type devraient vérifier que toutes les sous-classes de Utilisateur
doivent implémenter un constructeur avec une signature valide pour être instanciées de cette façon. Mon cas d'utilisation est différent car je pourrais ne pas construire le nouveau type, mais simplement retourner un type préexistant. Disons que je fais
class X: pass
class Enveloppe:
def __init__(self, x: X):
self._x = x
def into(self, t: Type[X]) -> X:
return self._x
tout fonctionne bien jusqu'à ce que quelqu'un crée une sous-classe de X
w = Enveloppe(X())
...
class XX(X): pass
x: XX = w.into(XX)
Le Côté droit est bon selon mypy car Type
est covariant, mais clairement l'API est cassée car un X
n'est pas un XX
. Si Type
n'était pas covariant, cela ne serait pas un problème : le Côté droit ne passerait pas la vérification du type tant que Enveloppe
n'était pas mise à jour pour supporter XX
.
Ma question est : y a-t-il un moyen d'atteindre cela (ou quelque chose de similaire) étant donné la covariance de Type
?
Contexte
Je veux utiliser ceci pour convertir un type en plusieurs autres types, en spécifiant le type désiré de manière explicite plutôt que simplement vers_X
, vers_Y
, etc. Je m'attends à le faire avec TypeVar
ou surcharger
. J'ai également des difficultés ici.
Cela est inspiré par le Into
de Rust, où t: Type[U]
est un paramètre de type et non un argument de fonction.