2

J'ai construit un décorateur de vérification de type (avec enveloppes):Python: vérification de type décorateur

def accepts_func(*types): 
    """ 
    top-level decoration, consumes parameters 
    """ 

    def decorator(func): 
     """ 
     actual decorator function, consumes the input function 
     """ 

     @wraps(func) 
     def check_accepts(*args): 
      """ 
      actual wrapper which does some magic type-checking 
      """ 

      # check if length of args matches length of specified types 
      assert len(args) == len(types), "{} arguments were passed to func '{}', but only {} " \ 
              "types were passed to decorator '@accepts_func'" \ 
       .format(len(args), func.__name__, len(types)) 

      # check types of arguments 
      for i, arg, typecheck in izip(range(1, len(args)+1), args, types): 
       assert isinstance(arg, typecheck), "type checking: argument #{} was expected to be '{}' but is '{}'" \ 
        .format(i, typecheck, type(arg)) 

      return func(*args) 

     return check_accepts 

    return decorator 

Vous pouvez passer autant de types que vous voulez et il vérifie si les types des paramètres passés à func correspondance ceux qui ont été « codées en dur » dans @accepts_func(param_type1, param_type2, ...):

@accepts_func(int, str) 
sample_func(arg1, arg2): 
    ...does something... 

Il fonctionne sans aucun problème jusqu'à présent.


Cependant, comme je ne suis pas un « gourou » Python Je voudrais savoir si ma solution est appropriée pour les projets « plus gros »?

Y a-t-il des inconvénients dans ma solution? E.g. comme les problèmes de performance, les erreurs non interceptées dans les cas de bord, et d'autres choses?

Existe-t-il un moyen d'améliorer ma solution? Faire mieux, plus de solutions "pythoniques" existent?

Note: Je ne vérifie pas toutes les fonctions de mon projet, seulement celles qui me semblent avoir vraiment besoin de sécurité. Le projet s'exécute sur un serveur, par conséquent, les erreurs lancées apparaissent dans les journaux et ne sont pas visibles pour l'utilisateur.

+2

N'utilisez pas d'assertions pour du code réel, si votre script est lancé avec python -O, les assertions seront ignorées. Utilisez-les uniquement dans les tests. – user312016

+0

Merci! Que suggérez-vous d'utiliser à la place? Comme la meilleure pratique? – daniel451

+0

Utilisez simplement les instructions if – user312016

Répondre

1

Je découragerais réellement de typecheck variables d'entrée. Performances mises à part, Python est un langage dynamiquement typé et dans certains cas (test, par exemple) vous devrez passer un objet qui implémente certains attributs de l'objet que vous avez initialement prévu d'encourager et qui fonctionnera correctement avec votre code.

Un exemple simple:

class fake_str: 
    def __init__(self, string): 
     self.string = string 

    def __str__(self): 
     return self.string 

string = fake_str('test') 

isinstance(string, str) # False 
string # 'test' 

Pourquoi ne pas accepter quelque chose qui travaille? Autorisez simplement les objets compatibles à fonctionner avec votre code.

Easier to ask for forgiveness than permission!

-1

Si vous voulez vérifier les types, utilisez python 3.5 et son module de typage qui prend en charge les indicateurs de type intégrés.

http://blog.jetbrains.com/pycharm/2015/11/python-3-5-type-hinting-in-pycharm-5/

EDIT:

En guise d'avertissement au lecteur. Tapez hinting dans une langue comme python peut être utile mais c'est aussi une douleur. Beaucoup d'API python sont hautement polymorphes, acceptant de nombreux types d'arguments différents et d'arguments optionnels. Les signatures de type sur ces fonctions sont gnarly et leur annotation n'est pas utile du tout. Mais pour les fonctions simples qui prennent et renvoient des types simples, l'indication de type ne peut qu'améliorer la clarté.