2017-09-20 5 views
0

J'ai besoin de mettre en œuvre beaucoup de fonctions qui ont la sélection des cas comme celui-ci:Comment afficher la liste des arguments juridiques lorsque l'entrée est illégale?

def foo1(bar1): 
    if bar1 == 'A': 
     do something 
    elif bar1 == 'B': 
     do something 
    elif ... 
    ... 
    else: 
     raise ValueError('legal input of bar1 should be {}'.format(list_of_bar)) 

def foo2(bar2): 
    if bar2 == 'A': 
     do something 
    elif bar2 == 'B': 
     do something 
    elif ... 
    ... 
    else: 
     raise ValueError('legal input of bar2 should be {}'.format(list_of_bar)) 

''' 

Selon « Ne répétez pas vous-même », est-il un moyen d'éviter de répéter la dernière étape d'une erreur de relance et imprimer la liste des arguments corrects? Je pensais qu'un décorateur pourrait le faire, mais je ne sais pas comment le faire. Merci d'avance.

mise à jour

je moi-même mis en œuvre avec l'inspection module. Mais je l'espère peut encore obtenir des conseils ou de meilleures solutions

import inspect 
from functools import wraps 
import re 

def test_none(func): 
    _code = inspect.getsource(func) 
    _list = re.findall(r'if (\w+) == (\w+)', _code) 
    assert all(_list[0][0] == name for name, case in _list) 
    _arg = _list[0][0] 
    _case = tuple(case for name, case in _list) 

    @wraps(func) 
    def wrapper(*args, **kwargs): 
     results = func(*args, **kwargs) 
     if results is None: 
      raise ValueError(
        'Legal value of \'{arg}\' should be anyone of {case}'.format(
        arg=_arg, case=_case)) 
     return results 
    return wrapper 

@test_none 
def foo(bar): 
    if bar == 0: 
     return 1 
    elif bar == 1: 
     return 2 

Exemple de test:

foo(3) 
ValueError: Legal value of 'bar' should be anyone of ('0', '1') 
+2

Vous cherchez quelque chose qui associe ' "A"' «faire quelque chose», «B» 'faire autre chose, etc. En d'autres termes, vous voulez un dict. –

+0

Mais avec un dictionnaire, je dois aussi faire l'erreur finale d'élévation et d'impression, que je veux vraiment éviter par un décorateur ou autre "magie noire". –

Répondre

1

Je trouve généralement que le modèle «de nombreux cas de est plus clairement exprimée avec des dictionnaires.

Je suppose ici que pour chaque cas nous avons une fonction différente que nous voulons appeler, mais le modèle fonctionne si chaque valeur est juste un entier que vous voulez retourner, ou tout autre objet.

par exemple. Le dictionnaire CASES signale clairement et de manière compacte au lecteur du code les différents cas.

CASES = { 
    'A': do_something, 
    'B': do_something_else, 
    ... 
} 

def foo(bar): 
    if bar not in CASES: 
     raise ValueError('legal input of bar should be {}'.format(list_of_bar)) 

    # do stuff 
    CASES[bar]() 

Une alternative consiste à utiliser le modèle «demander pardon, pas d'autorisation». Je trouve dans ce cas particulier que ce n'est pas aussi clair que ce qui précède.

def foo(bar): 
    try: 
     func = CASES[bar] 
    except KeyError: 
     raise ValueError(...) 
    # do stuff 
    func() 

ou utiliser la méthode dictionnaire .get comme une autre façon, mais encore une fois je pense qu'il est pas aussi clair que la première voie à ce scénario.

def foo(bar): 
    func = CASES.get(bar) 
    if func is None: 
     raise ValueError(...) 
    # do stuff 
    func() 
+0

J'aime toutes ces réponses - et je pense qu'il y a de bons exemples d'utilisation pour chaque paradigme. Bon travail! –

+0

Merci pour la réponse. Mais si j'ai beaucoup de fonction similaire à définir, il y a aussi beaucoup de redondance de la structure globale. Je me demandais s'il y avait un moyen de prendre la fonction "foo" sans l'étape d'erreur d'augmentation, puis cracher une nouvelle fonction avec l'étape finale. –

1

Utilisez un dictionnaire pour cartographier les entrées possibles actions, quelque chose comme ceci:

def foo(bar): 
    def a(): 
     print('a():') 

    def b(): 
     print('b():') 

    def c(): 
     print('c():') 

    actions = {'A': a, 'B': b, 'C': c} 
    if bar in actions: 
     actions[bar]() 
    else: 
     raise ValueError('legal input of bar should be {}'.format(sorted(actions.keys()))) 

Démo:

>>> foo('A') 
a(): 
>>> foo('Z') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "x.py", line 15, in foo 
    raise ValueError('legal input of bar should be {}'.format(sorted(actions.keys()))) 
ValueError: legal input of bar should be ['A', 'B', 'C'] 
+0

Oui dictionnaire fonctionne très bien dans ce cas. Désolé si je ne l'ai pas exprimé clairement, mais ce dont j'ai besoin est d'éviter l'étape finale "raise ValueError". Parce que j'ai besoin d'un tas de fonctions différentes ayant cette structure similaire, je pensais à y at-il un moyen de contourner l'erreur d'augmentation répétée et l'étape d'impression. J'ai pensé que cela pourrait nécessiter une métaprogrammation. –