2009-03-29 6 views
1

Tenir compte de ce segment Python:Raccourcir un segment de code souvent utilisé pour tester une valeur de retour en Python

def someTestFunction(): 
    if someTest: 
     return value1 
    elif someOtherTest: 
     return value2 
    elif yetSomeOtherTest: 
     return value3 
    return None 

def SomeCallingFunction(): 
    a = someTestFunction() 
    if a != None: 
     return a 

    ... normal execution continues 

Maintenant, la question suivante: le segment de trois lignes au début de SomeCallingFunction pour obtenir la valeur de la fonction de test et de sauvetage si ce n'est pas Aucun, est répété très souvent dans de nombreuses autres fonctions. Trois lignes sont trop longues. Je veux le raccourcir à un. Comment je fais ça?

Je peux restructurer librement ce code et le contenu de someTestFunction cependant nécessaire. J'ai pensé utiliser des exceptions, mais celles-ci ne semblent pas aider à réduire la longueur du code appelant.

(je l'ai lu un peu de décorateurs Python, mais ne les ai pas utilisé. Serait-ce l'endroit? Comment ça marche?)

+0

donc juste calrify ... si la fonction est Aucun continue et retourne autre chose? – hasen

+0

Correct, "l'exécution normale continue" signifie que la fonction fait quelque chose qu'elle ne devrait faire que lorsque someTestFunction a retourné None. – Jaanus

+0

Juste une note qu'il est légèrement moins efficace de tester "! = None" plutôt que "is not None" (voir PEP290). – chradcliffe

Répondre

9

Si vous souhaitez utiliser un décorateur, il ressemblerait à ceci:

def testDecorator(f): 
    def _testDecorator(): 
     a = someTestFunction() 
     if a is None: 
      return f() 
     else: return a 
    return _testDecorator 

@testDecorator 
def SomeCallingFunction(): 
    ... normal execution 

Lorsque le module est d'abord importé, il exécute testDecorator, en lui transmettant votre SomeCallingFunction d'origine en tant que paramètre. Une nouvelle fonction est renvoyée et celle-ci est liée au nom SomeCallingFunction. Maintenant, chaque fois que vous appelez SomeCallingFunction, il exécute cette autre fonction, qui effectue la vérification, et renvoie soit a, soit le résultat de l'original SomeCallingFunction.

+0

Merci. Les décorateurs semblent les plus appropriés pour mon cas, et c'est une bonne explication. hasen j a offert une version de ceci, mais je n'ai pas besoin de spécifier dynamiquement la fonction de test, il est plus clair pour moi si c'est codé en dur. Bon pour apprendre de nouvelles choses :) – Jaanus

4

J'utilise souvent une table de hachage en place d'une série de elifs:

def someTestFunction(decorated_test): 
    options = { 
     'val1': return_val_1, 
     'val2': return_val_2 
    } 
    return options[decorated_test] 

Vous pouvez définir des options comme defaultdict (Aucun) aux réglages par défaut sur Aucun si une clé est introuvable.

Si vous ne pouvez pas obtenir vos tests sous cette forme, alors une série d'instructions if pourrait être la meilleure chose à faire.

Une petite chose que vous pouvez faire pour réduire votre code est d'utiliser ceci:

if a: return a 

Il peut y avoir d'autres moyens de réduire votre code, mais ce sont ceux que je peux venir avec sur place.

+0

Merci. Pour someTestFunction, je ne me soucie pas de la longueur puisque le code n'est pas répété, donc la série d'instructions est correcte. "si a: return a" est à mi-chemin, mais j'ai encore besoin de capturer la valeur de retour de la fonction dans a. Nous sommes donc passés de 3 lignes à 2. Comment puis-je pousser plus loin? :) – Jaanus

2

Je pense que ce serait le faire:

MISE À JOUR fixe!
Désolé pour hier, je me suis précipité et n'ai pas testé le code!

def test_decorator(test_func): 
    def tester(normal_function): 
     def tester_inner(): 
      a = test_func() 
      if a is not None: 
       return a 
      return normal_function() 
     return tester_inner  
    return tester 


#usage: 
@test_decorator(my_test_function) 
def my_normal_function(): 
    #.... normal execution continue ... 

Il est similaire à la réponse de DNS mais vous permet de spécifier la fonction test que vous souhaitez utiliser

+0

Ce n'est pas correct; test_decorator() retournera la fonction testeur, qui sera ensuite utilisée comme décorateur de my_normal_function. Pour que cela fonctionne, vous avez besoin d'une autre couche de fonction entre test_decorator et testeur. – Miles

+0

Fixé. Merci d'avoir signalé mon erreur. – hasen

Questions connexes