2009-10-09 7 views
2

Je suis encore un peu novice en Python, alors j'essaie de comprendre comment faire cela et j'ai besoin d'aide. J'utilise des codes de retour pour vérifier que mes fonctions internes retournent avec succès. Par exemple (des fonctions de bibliothèques):Condenser cette instruction Python sans détruire la lisibilité

result = some_function(arg1,arg2) 
if result != OK: return result 

ou (à partir du niveau du script principal):

result = some_function(arg1,arg2) 
if result != OK: abort_on_error("Could not complete 'some_function': %s" % messages(result)) 

Puis-je obtenir cela à une ligne sans la rendre illisible?

EDIT: Certaines personnes reconnaissent que les exceptions peuvent être un meilleur choix. Je voulais enregistrer les exceptions uniquement pour la capture de scénarios très «exceptionnelle». On peut s'attendre à ce que les codes de retour échouent parfois, et j'ai pensé que c'était généralement une mauvaise pratique d'utiliser des exceptions pour ce scénario.

+2

Semble assez condensé pour moi.Trop, en fait, je dirais que l'abandon sur erreur devrait être sur sa propre ligne. –

+0

Assez juste. Les one-liner sont-ils si "pythonic"? Habituellement, le langage vous pousse à utiliser la syntaxe 'pythonic', mais cela rend cela disponible. – cgyDeveloper

+0

Les instructions 'if' à une ligne sont déconseillées, voir le guide de style Python, PEP8 http://www.python.org/dev/peps/pep-0008/ – dbr

Répondre

3

On dirait que vous voulez quelque chose comme ..

if result = some_function(arg1, arg2): 
    return result 

Ceci est délibérément impossible en Python. Il est trop courant d'écrire une faute de frappe if a = b au lieu de if a == b, et de permettre cette affectation de mélanges avec le contrôle de flux. Si cela est nécessaire, diviser en deux lignes:

x = some_function() 
if x: 
    print "Function returned True" 

Un exemple plus pratique de c'est ..

result = re.match("a", "b") 
if result: 
    print result.groups() 

(plus correctement, vous devriez faire if result is not None: dans ce cas, bien que les travaux ci-dessus

Dans votre cas spécifique ("pour vérifier que mes fonctions internes fonctionnent correctement"), il semble que vous deviez utiliser des exceptions. Si tout va bien, renvoyez simplement ce que vous voulez. Si quelque chose se passe mal, déclenchez une exception.

exceptions en Python ne sont pas comme beaucoup d'autres langues - par exemple, ils sont utilisés en interne flux de contrôle (comme l'exception StopIteration)

Je considérerais comme suit loin plus Pythonic que d'utiliser les codes de retour :

#!/usr/bin/env python2.6 
def some_function(arg1, arg2): 
    if arg1 + arg2 > 5: 
     return "some data for you" 
    else: 
     raise ValueError("Could not complete, arg1+arg2 was too small") 

Ensuite, vous pouvez appeler la fonction en une seule ligne:

return some_function(3, 2) 

Ce soit renvoie la valeur, ou déclenche une exception, que vous pouvez gérer l'exception quelque part raisonnable:

def main(): 
    try: 
     result = some_function(3, 5) 
    except ValueError, errormsg: 
     print errormsg 
     sys.exit(1) 
    else: 
     print "Everything is perfect, the result was {0}".format(result) 

Ou si ce cas est en fait une erreur, laissez simplement arrêter l'application avec une belle trace de la pile.

Oui, c'est beaucoup plus long qu'une ligne, mais l'idée derrière Python est la brièveté, mais l'explicitation et la lisibilité.

Fondamentalement, si la fonction ne peut plus continuer, déclencher une exception. Manipuler cette exception soit où vous pouvez récupérer du problème, ou présenter l'utilisateur avec un message d'erreur .. sauf si vous écrivez une bibliothèque, dans ce cas laissez l'exception pour monter la pile au code appelant

ou, sous forme de poème:

$ python -m this 
The Zen of Python, by Tim Peters 

Beautiful is better than ugly. 
Explicit is better than implicit. 
Simple is better than complex. 
Complex is better than complicated. 
Flat is better than nested. 
Sparse is better than dense. 
Readability counts. 
Special cases aren't special enough to break the rules. 
Although practicality beats purity. 
Errors should never pass silently. 
Unless explicitly silenced. 
In the face of ambiguity, refuse the temptation to guess. 
There should be one-- and preferably only one --obvious way to do it. 
Although that way may not be obvious at first unless you're Dutch. 
Now is better than never. 
Although never is often better than *right* now. 
If the implementation is hard to explain, it's a bad idea. 
If the implementation is easy to explain, it may be a good idea. 
Namespaces are one honking great idea -- let's do more of those!

Enfin, il pourrait être utile de lire sur "PEP 8", le guide de style pour Python. Il peut répondre à certaines de vos questions, telles que "Est-ce que les déclarations 'one-liner' sont pythoniques '?"

Les instructions composées (plusieurs instructions sur la même ligne) sont généralement déconseillées.

Oui:

if foo == 'blah': 
    do_blah_thing() 
do_one() 
do_two() 
do_three() 

plutôt pas:

if foo == 'blah': do_blah_thing() 
do_one(); do_two(); do_three() 
+0

Juste, quand j'ai découvert que la première déclaration que vous avez écrit n'est pas possible, je suis venu ici pour des suggestions. Je suppose que ce n'est pas là. Je vais revoir ma logique de codes/exceptions, cependant, basé sur tant de suggestions. – cgyDeveloper

10

Pourriez-vous utiliser des exceptions pour indiquer un échec plutôt que des codes de retour? Alors la plupart de vos déclarations if result != OK: disparaîtraient simplement.

+6

Je suis d'accord. Les codes de retour ne sont pas très "pythoniques", ou considérés comme une bonne pratique dans toute langue moderne que je peux penser. –

+0

Je voulais enregistrer des exceptions pour les cas «exceptionnels». Ces fonctions peuvent renvoyer ces codes. J'ai toujours pensé que c'était une mauvaise pratique de compter sur des exceptions pour autre chose que d'attraper des scénarios exceptionnels. – cgyDeveloper

+0

Cela ne va-t-il pas créer une série de blocs try/except, alors? Ou y a-t-il une syntaxe de manipulation élégante que je ne connais pas. – cgyDeveloper

3

pythonic:

Une idée ou un morceau de code qui suit de près idiomes les plus courantes du langage Python, plutôt que de mettre en œuvre le code en utilisant des concepts communs à d'autres langues [...]

.

N'implique pas d'écrire sur les liners!

+0

Peut-être qu'il n'y a pas de bonne syntaxe pour cela. Je voulais voir ce que les plus familiers de la langue trouveraient. – cgyDeveloper

+1

pour cela, vous devez fournir un code réel – SilentGhost

1

Si vous insistez sur ne pas utiliser exceptions, je voudrais écrire deux lignes (une ligne sera trop long ici):

res = some_function(arg1, arg2) 
return res if res != OK else ... 

Soit dit en passant, je vous recommande de trouver des static type de valeurs renvoyées par votre fonction (malgré le typage dynamique en Python). Par exemple, vous pouvez renvoyer "int ou None". Vous pouvez mettre une telle description dans une docstring.

Si vous avez int valeurs de résultat et int codes d'erreur que vous pouvez les distinguer en introduisant une classe d'erreur:

class ErrorCode(int): pass 

puis vérifier si le résultat isinstance de ErrorCode.

-1

En plus des exceptions, en utilisant un décorateur est une bonne solution à ce problème:

# Create a function that creates a decorator given a value to fail on... 
def fail_unless(ok_val): 
    def _fail_unless(f): 
     def g(*args, **kwargs): 
      val = f(*args, **kwargs) 
      if val != ok_val: 
       print 'CALLING abort_on_error...' 
      else: 
       return val 
     return g 
    return _fail_unless 


# Now you can use the decorator on any function you'd like to fail 
@fail_unless('OK') 
def no_negatives(n): 
    if n < 0: 
     return 'UH OH!' 
    else: 
     return 'OK' 

En pratique:

>>> no_negatives(9) 
'OK' 
>>> no_negatives(0) 
'OK' 
>>> no_negatives(-1) 
'CALLING abort_on_error...' 

Je sais que la syntaxe définit fail_unless est un peu délicat si vous re pas utilisé pour les décorateurs et les fermetures de fonction, mais l'application de fail_unless() est assez agréable non?

Questions connexes