Python Language
Anti-Patterns Python
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:
- L'
except
sans type d'exception (ligne 5) attraperez exceptions même en bonne santé, y comprisKeyboardInterrupt
. Cela empêchera le programme de sortir dans certains cas. - 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 queres
était une liste vide. - 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, augmenteraNameError
, 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.