Lorsqu’on commence à apprendre le langage Python, on prend (souvent) de mauvaises habitudes de codage dont nous ne sommes pas conscients. C’est pourquoi je vous partage 10 erreurs en Python que j’ai découvert au cours de mes années de data scientist.
Il se peut que vous écriviez du code qui fait le job une fois mais qui risque d’échouer à l’avenir, ou que vous utilisiez des solutions de contournement alors qu’il existe une fonction intégrée qui pourrait vous faciliter la vie.
Les 10 erreurs en Python que je vous ai séléctionnées
Et la plupart d’entre nous cumulent même plusieurs de ces mauvaises habitudes en Python (qui datent de des premiers mois d’apprentissage). La bonne nouvelle c’est que vous pouvez facilement les corriger aujourd’hui avec les extraits de code ci-dessous.
À chaque fois, je vous donne 2 fragments de code : la mauvaise pratique suivie immédiatement de la bonne pratique à adopter (et parfois des solutions alternatives).
Erreur 1 – Utilisation de import *
Il est très tentant d’importer tout ce qui se trouve dans un module en utilisant la commande from xyz import *
Ce n’est pas une bonne pratique pour de nombreuses raisons.
En voici quelques-unes :
- Elle peut être inefficace : Si le module comporte un grand nombre d’objets, vous devrez attendre longtemps avant que tout soit importé.
- Elle peut provoquer des conflits entre les noms de variables : Lorsque vous utilisez le *, vous ne savez pas quels objets vous importez ainsi que leurs noms.
Comment résoudre ce problème ?
Importez soit l’objet spécifique que vous prévoyez d’utiliser, soit le module entier.
# IMPORT * ##################### # Mauvaise pratique # ##################### from math import * print(floor(2.4)) print(ceil(2.4)) print(pi) ################## # Bonne pratique # ################## import math from math import pi print(math.floor(2.4)) print(math.ceil(2.4)) print(pi)
Erreur 2 – Try / Except : Ne pas spécifier l’exception dans la clause « except »
Cette erreur je l’ai ignoré pendant longtemps…
Je ne compte plus le nombre de fois où Pycharm m’a fait savoir (avec ces affreux soulignements…) que je ne devais pas utiliser un except seul (sans rien après). Ce n’est d’ailleurs pas recommandé dans les directives PEP 8 (voir erreur 5 pour plus de détails sur ce point).
# TRY - EXCEPT # Mauvaise pratique try: driver.find_element(...) except: print("Quelle exception ?") # Bonne pratique try: driver.find_element(...) except NoSuchElementException: print("Cela donne NoSuchElementException") except ElementClickInterceptedException: print("Cela donne ElementClickInterceptedException")
Le problème avec un except tout nu, c’est qu’il attrapera les exceptions SystemExit et KeyboardInterrupt, ce qui rendra plus difficile l’interruption d’un programme avec Control-C.
La prochaine fois que vous utiliserez try/except, please spécifiez l’exception dans la clause except, vraiment 🙂
Erreur 3 – Ne pas utiliser NumPy pour les calculs mathématiques
On oublie souvent qu’il existe des paquets qui peuvent nous rendre la vie plus facile et plus productive en Python.
L’un de ces paquets que vous devriez utiliser pour les calculs mathématiques est NumPy. NumPy peut vous aider à résoudre des opérations mathématiques plus rapidement que les boucles for
.
Supposons que nous ayons un tableau de random_scores et que nous voulions obtenir le score moyen de ceux qui ont échoué à l’examen (score < 70). Essayons de résoudre ce problème avec une boucle for.
# Génération de scores aléatoires import numpy as np random_scores = np.random.randint(1, 100, size=10000001)
# Mauvaise pratique (résolution du problème avec une boucle) count_failed = 0 sum_failed = 0 for score in random_scores: if score < 70: sum_failed += score count_failed += 1 print(sum_failed/count_failed)
Maintenant, résolvons ce problème avec NumPy.
# Bonne pratique (résolution du problème en utilisant des opérations vectorielles) mean_failed = (random_scores[random_scores < 70]).mean() print(mean_failed)
Si vous exécutez les deux, vous verrez que NumPy est plus rapide. Pourquoi ? Parce que NumPy vectorise nos opérations.
Erreur 4 – Ne pas fermer un fichier précédemment ouvert
Une bonne pratique que tout le monde connaît c’est que chaque fichier que nous ouvrons avec Python doit être fermé.
C’est pourquoi nous utilisons les méthodes open, write/read, close lorsque nous travaillons avec des fichiers. C’est bien, mais si les méthodes write/read lèvent une exception, le fichier ne sera pas fermé.
Pour éviter ce problème, nous devons utiliser l’instruction with
. Celle-ci fermera le fichier même s’il y a une exception.
# Mauvaise pratique f = open('dataset.txt', 'w') f.write('new_data') f.close() # Bonne pratique with open('dataset.txt', 'w') as f: f.write('new_data')
Erreur 5 – Ne pas suivre le PEP8
PEP8 est un document que toute personne apprenant Python devrait lire. Il fournit des directives et des bonnes pratiques sur la façon d’écrire du code Python (certains des conseils de cet article proviennent de PEP8).
Ces directives peuvent être intimidantes pour ceux qui découvrent Python. Heureusement, certaines règles PEP8 sont intégrées dans les IDE (c’est ainsi que j’ai connu la règle du except).
Supposons que vous utilisez Pycharm. Si vous écrivez du code qui ne suit pas les directives PEP8, vous verrez ces vilains soulignements dans l’image ci-dessous.
Si vous survolez les soulignements, vous verrez des instructions sur la façon de les corriger.
Dans mon cas, je dois seulement ajouter un espace blanc après ,
et :
# Good my_list = [1, 2, 3, 4, 5] my_dict = {'key1': 'value1', 'key2': 'value2'} my_name = "Rod"
J’ai également changé le nom de ma variable x en my_name. Ce n’est pas suggéré par Pycharm, mais PEP8 recommande d’utiliser des noms de variables faciles à comprendre.
Erreur 6 – Utilisation incorrecte des méthodes .keys et .values avec des dictionnaires
Je pense que la plupart d’entre vous savent ce que font les méthodes .keys et .values lorsque vous travaillez avec des dictionnaires.
Au cas où vous ne le sauriez pas, jetez un coup d’œil à ce qui suit :
dict_countries = {'France': 67.4, 'Spain': 47.3, 'Portugal': 10.3} >>>dict_countries.keys() dict_keys(['France', 'Spain', 'Portugal']) >>>dict_countries.values() dict_values([67.4, 47.3, 10.3])
Mais le problème c’est que parfois nous ne les utilisons pas correctement.
Imaginons que nous voulions parcourir le dictionnaire avec une boucle et obtenir les clés. Vous pourriez utiliser la méthode .keys, mais saviez-vous que vous pouviez obtenir les clés en parcourant le dictionnaire avec une boucle ? Dans ce cas, l’utilisation de .keys sera inutile.
# .keys() # Mauvaise pratique for key in dict_countries.keys(): print(key) # Bonne pratique for key in dict_countries: print(key)
De même, nous pourrions trouver des solutions de contournement pour obtenir les valeurs d’un dictionnaire, mais celles-ci pourraient être facilement obtenues avec la méthode .items().
# .items() # Mauvaise pratique for key in dict_countries: print(dict_countries[key]) # Bonne pratique for key, value in dict_countries.items(): print(key) print(value)
Erreur 7 – Ne jamais utiliser les compréhensions (ou les utiliser tout le temps)
La compréhension offre une syntaxe plus courte lorsque l’on veut créer une nouvelle séquence (liste, dictionnaire, etc.) à partir d’une séquence déjà définie.
Supposons que nous voulions mettre en minuscules tous les éléments de notre liste countries de pays.
Bien que vous puissiez le faire avec une boucle for, vous pouvez simplifier les choses avec une compréhension de liste.
# Mauvaise pratique countries = ['France', 'Spain', 'Portugal'] lower_case = [] for country in countries: lower_case.append(country.lower()) # Bien (mais n'en abusez pas !) lower_case = [country.lower() for country in countries]
Les compréhensions sont très utiles, mais n’en abusez pas ! Rappelez-vous The Zen of Python : « Simple is better than complex ».
Erreur 8 – Utilisation de range(len())
L’unes des premières fonctions que l’on apprend en tant que débutants sont range et l’en, il n’est donc pas étonnant que la plupart des gens aient la mauvaise habitude d’écrire range(len()) lorsqu’ils bouclent des listes.
Supposons que nous avons une liste countries de pays et une liste populations. Si nous voulons itérer à travers les deux listes en même temps, vous utiliserez probablement range(len()).
# Using range(len()) countries = ['France', 'Spain', 'Portugal'] populations = [67.4, 47.3, 10.3] # Mauvaise pratique for i in range(len(countries)): country = countries[i] population = populations[i] print(f"{country} a une population de {population} millions d'habitants")
Bien que cela fasse le job, vous pouvez simplifier votre code en utilisant enumerate (ou mieux encore, utiliser la fonction zip pour associer les éléments des deux listes).
# OK for i, country in enumerate(countries): population = populations[i] print(f"{country} a une population de {population} millions d'habitants") # Bien mieux for country, population in zip(countries, populations): print(f"{country} a une population de {population} millions d'habitants")
Erreur 9 – Formatage avec l’opérateur +
L’une des premières choses que nous apprenons en Python est probablement la façon de joindre des chaînes de caractères (string) avec l’opérateur +
.
Il s’agit d’un moyen utile, mais inefficace, de joindre des strings en Python. De plus, elle n’est pas très esthétique – plus vous devez joindre de chaînes, plus vous utiliserez de +.
Au lieu d’utiliser cet opérateur, vous pouvez utiliser la f-string.
# Formatage avec l'opérateur + # Mauvaise pratique name = input("Entre ton prénom : ") print("Bonjour, " + name + "!") # Bonne pratique name = input("Entre ton prénom : ") print(f'Bonjour, {name}')
La meilleure partie de f-strings c’est qu’il n’est pas seulement utile pour la concaténation mais a en plus des applications différentes.
Erreur 10 – Utilisation de valeurs mutables par défaut
Si vous incluez une valeur mutable (comme une liste) comme paramètre par défaut d’une fonction, vous verrez un comportement inattendu.
# Mauvaise pratique def my_function(i, my_list=[]): my_list.append(i) return my_list >>> my_function(1) [1] >>> my_function(2) [1, 2] >>> my_function(3) [1, 2, 3]
Dans le code ci-dessus, à chaque fois que nous appelons la fonction my_function, la liste my_list continue de sauvegarder les valeurs des appels précédents (il est probable que nous voulions initier une liste vide à chaque fois que nous appelons la fonction).
Pour éviter ce comportement, nous devons définir ce paramètre my_list égal à None et inclure la clause if ci-dessous.
# Bonne pratique def my_function(i, my_list=None): if my_list is None: my_list = [] my_list.append(i) return my_list >>> my_function(1) [1] >>> my_function(2) [2] >>> my_function(3) [3]
J’espère que cette lecture vous a plu ! N’hésitez pas à indiquer en commentaire combien de ces mauvaises habitudes (parmi les 10 cités) vous aviez conservé de vos débuts avec Python 🙂
Et pour aller plus loin sur Python : voici 25 extraits de code Python pour votre travail quotidien.