Recherche…


Trop zélé sauf clause

Les exceptions sont puissantes, mais une seule clause trop zélée peut éliminer tout cela en une seule ligne.

try:
    res = get_result()
    res = res[0]
    log('got result: %r' % res)
except:
    if not res:
        res = ''
    print('got exception')

Cet exemple montre 3 symptômes de l'anti-motif:

  1. L' except sans type d'exception (ligne 5) attraperez exceptions même en bonne santé, y compris KeyboardInterrupt . Cela empêchera le programme de sortir dans certains cas.
  2. Le bloc d'exception ne relance pas l'erreur, ce qui signifie que nous ne pourrons pas dire si l'exception provient de get_result ou parce que res était une liste vide.
  3. Pire encore, si nous craignions que le résultat soit vide, nous avons causé quelque chose de bien pire. Si get_result échoue, res restera complètement désactivé et la référence à res dans le bloc except, augmentera NameError , masquant complètement l'erreur d'origine.

Pensez toujours au type d'exception que vous essayez de gérer. Donnez une lecture à la page des exceptions et obtenez une idée des exceptions de base.

Voici une version fixe de l'exemple ci-dessus:

import traceback

try:
    res = get_result()
except Exception: 
    log_exception(traceback.format_exc())
    raise
try:
    res = res[0]
except IndexError:
    res = ''

log('got result: %r' % res)

Nous attrapons des exceptions plus spécifiques, en les relançant si nécessaire. Quelques lignes de plus, mais infiniment plus correctes.

Avant de sauter avec une fonction gourmande en processeurs

Un programme peut facilement perdre du temps en appelant plusieurs fois une fonction gourmande en processeurs.

Par exemple, prenez une fonction qui ressemble à ceci: elle retourne un entier si la value entrée peut en produire une, sinon None :

def intensive_f(value): # int -> Optional[int]
   # complex, and time-consuming code
   if process_has_failed:
       return None
   return integer_output

Et il pourrait être utilisé de la manière suivante:

x = 5
if intensive_f(x) is not None:
    print(intensive_f(x) / 2)
else:
    print(x, "could not be processed")

print(x)

Bien que cela fonctionne, il a pour problème d'appeler intensive_f , ce qui double la durée d'exécution du code. Une meilleure solution serait d'obtenir la valeur de retour de la fonction au préalable.

x = 5
result = intensive_f(x)
if result is not None:
    print(result / 2)
else:
    print(x, "could not be processed")

Cependant, une manière plus claire et peut - être plus pythonique consiste à utiliser des exceptions, par exemple:

x = 5
try:
    print(intensive_f(x) / 2)
except TypeError: # The exception raised if None + 1 is attempted
    print(x, "could not be processed")

Ici, aucune variable temporaire n'est nécessaire. Il est souvent préférable d'utiliser une instruction assert et d'attraper l' AssertionError place.

Clés de dictionnaire

Un exemple courant de l'endroit où cela se trouve est l'accès aux clés du dictionnaire. Par exemple comparer:

bird_speeds = get_very_long_dictionary()

if "european swallow" in bird_speeds:
    speed = bird_speeds["european swallow"]
else:
    speed = input("What is the air-speed velocity of an unladen swallow?")

print(speed)

avec:

bird_speeds = get_very_long_dictionary()

try:
    speed = bird_speeds["european swallow"]
except KeyError:
    speed = input("What is the air-speed velocity of an unladen swallow?")

print(speed)

Le premier exemple doit parcourir le dictionnaire deux fois, et comme il s'agit d'un long dictionnaire, cela peut prendre beaucoup de temps à chaque fois. La seconde ne nécessite qu'une seule recherche dans le dictionnaire, ce qui économise beaucoup de temps processeur.

Une alternative à ceci est d'utiliser dict.get(key, default) , cependant de nombreuses circonstances peuvent nécessiter des opérations plus complexes dans le cas où la clé n'est pas présente.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow