2017-09-14 2 views
2

Eh bien, je considère un cas où j'ai un baseclass avec (plusieurs) enfants. J'ai une fonction qui prend une liste d'objets de baseclass et retourne une nouvelle liste avec ces objets dedans.indice de type python, retourne le même type que l'entrée

Maintenant, si j'utiliser une classe d'enfants de toute évidence le retour est une liste de ces objets de classe enfant: considérer le cas trivial suivant:

from typing import Sequence, List, TypeVar 


class BaseClass: 
    def __init__(self, data=None, *args, **kwargs): 
     super().__init__() 
     self.CanCalculate = True 
     if data is None: 
      data = [] 
      self.CanCalculate = False 
     self._mydata = list(data) 
     self.multiplier = 1 

    @property 
    def data(self): 
     return self._mydata 


class ChildClass(BaseClass): 
    def sum_mul_data(self): 
     return self.multiplier * sum(self.data) 


class SecondChildClass(BaseClass): 
    def sum_div_data(self): 
     return sum(self.data)/self.multiplier 


def myFun(input: Sequence[BaseClass]) -> List[BaseClass]: 
    out = [] 
    for n, i in enumerate(input): 
     if i.CanCalculate: 
      i.multiplier = 10**n 
      out.append(i) 
    return out 


childs = [ChildClass([1,2,3,4]), ChildClass(), ChildClass([1,2,3,4])] 

t = myFun(childs) 
for idx in t: 
    print(idx.sum_mul_data()) 


childs = [SecondChildClass([1,2,3,4]), SecondChildClass(), SecondChildClass([1,2,3,4])] 

t = myFun(childs) 
for idx in t: 
    print(idx.sum_div_data()) 

Code juridique: cependant PyCharm (et les astuces de type standard) montre une erreur lors de l'analyse de code statique:

Maintenant, apparemment, cela est dû à pycharm en pensant que le retour de la fonction est de type "BaseClass" - pas un enfant. Alors, comment pourrais-je déclarer: "retourner le même type que l'entrée"?

J'ai essayé d'utiliser un typevar: T = TypeVar("T", BaseClass), bien que cela ait donné une erreur réelle, qu'une seule contrainte ne puisse pas être utilisée dans TypeVar. Fait intéressant en utilisant T = TypeVar("T", BaseClass, ChildClass) a travaillé, et pycharm déduit correctement le type (indice) pour sum_div_data.

+0

Vous semblez avoir résolu votre propre problème. Docs semble dire que 'T = TypeVar (" T ")' vous donnera un indice de type totalement générique et, comme vous l'avez vu, votre 'T = TypeVar (" T ", BaseClass, ChildClass)' fonctionne. – quamrana

+0

@quamrana mais cela signifierait que l'emplacement de 'myFun' a une compréhension d'au moins une telle classe enfant. - En plus de cela, il semble totalement arbitraire pourquoi la référence à la 'ChildClass' est là: pourquoi pas une référence à' SecondChildClass' ou quelque chose d'autre? – paul23

Répondre

1

Vous devriez utiliser des caractères avec une limite supérieure: faites T = TypeVar('T', bound=BaseClass) au lieu de T = TypeVar('T', BaseClass).

Détails:

  • Quand vous faites quelque chose comme T = TypeVar('T', ClassA, ClassB, ClassC...), vous créez un type variable with a value restriction. Autrement dit, vous insistez que T doit être exactement l'une des classes que vous avez énumérées.

    C'est pour cette raison que T = TypeVar('T', ClassA) n'est pas autorisé: le typevar ne peut être égal qu'à une classe, donc il vaut mieux utiliser le type ClassA directement. Lorsque vous faites quelque chose comme T = TypeVar('T', bound=ClassA), vous créez un type variable with an upper bound. Vous insistez pour que T soit ClassA, soit l'une de ses sous-classes.