Par Maxime Jumelle
CTO & Co-Founder
Publié le 29 oct. 2020
Catégorie Machine Learning
Tu as peut-être déjà remarqué le symbole @
à proximité des fonctions avec Python. Il s'agit de décorateurs de fonctions.
Mais à quoi peuvent-ils servir ? En quelques lignes de code, nous allons voir comment créer des décorateurs de fonctions Python qui peuvent nous faciliter la vie.
Prenons un cas concret : on souhaite mesurer la durée d'exécution d'une fonction. Pour cela, nous importons la librairie time
et avec le code suivant, nous allons mesurer le temps d'exécution de la fonction pause
.
1import time
2
3def pause():
4 print("Début ...")
5 time.sleep(2) # Pause de 2 secondes
6 print("Fin !")
7
8start_time = time.time() # Temps avant exécution
9pause()
10end_time = time.time() # Temps après exécution
11print("Durée d'exécution : {:1.3}s".format(end_time - start_time))
Le problème, c'est qu'à chaque fois que l'on souhaitera mesurer la durée d'exécution d'une fonction, il faudra copier-coller l'affectation aux variables start_time
et end_time
, puis afficher la durée avec un print
.
À lire aussi : découvrez notre formation MLOps
C'est ici que les décorateurs de fonctions vont nous être utile. Elles viennent englober une fonction et vont permettrent, par exemple, d'exécuter des instructions avant ou après l'exécution de la fonction.
1def timing(func):
2 """
3 Mesure le temps d'exécution d'une fonction.
4 """
5 def wrapper():
6 start_time = time.time()
7 func()
8 end_time = time.time()
9 print("Durée d'exécution : {:1.3}s".format(end_time - start_time))
10
11 return wrapper
Analysons ce code.
timing
attends un paramètre, la fonction dont nous allons calculer la durée d'exécution.timing
, nous avons crée une fonction wrapper
qui sera renvoyée par la fonction timing
.wrapper
va calculer le temps avant puis après l'exécution de la fonction et afficher la durée avec un print
.Maintenant, pour mesurer la durée d'exécution de la fonction pause
, il suffit d'appeler la fonction timing
avec, comme paramètre, la fonction pause
.
1timing(pause)()
En écrivant timing(pause)
, j'obtiens la fonction wrapper
qui va exécuter à l'intérieur la fonction pause
.
⚠️ timing(pause)
est une fonction Python, d'où la présence des parenthèses pour l'exécuter.
Mais plutôt que d'utiliser cette écriture à chaque exécution de la fonction pause
, un décorateur de fonction va effectuer la même opération.
1@timing # La fonction timing(pause) sera exécuté à chaque appel de la fonction pause
2def pause():
3 print("Début ...")
4 time.sleep(2) # Pause de 2 secondes
5 print("Fin !")
Dorénavant, dès que l'on appelera la fonction pause
, la durée d'exécution sera automatiquement calculée et affichée.
1pause()
Une situation qui arrive souvent, c'est lorsque la fonction décorée, en l'occurrence ici la fonction pause
, s'attend à avoir des paramètres.
1@timing
2def pause(t):
3 print("Début ...")
4 time.sleep(t) # Pause de t secondes
5 print("Fin !")
Le paramètre t
indique ici la durée de la pause. Si maintenant, on appelle la fonction pause
avec comme argument t=2
.
1pause(t=2)
Une erreur apparaît ! 😨
Pourquoi y a-t-il une erreur ? Pour rappel, appeler la fonction pause
revient à appeler timing(pause)
. Or, le paramètre spécifié ici n'est pas envoyé à pause
mais à timing(pause)
(c'est-à-dire au wrapper
).
❓ Comment faire pour que les paramètres ne soient pas envoyés au
wrapper
mais à la fonctionpause
?
Il suffit de rajouter des arguments dans la fonction wrapper
:
1def timing(func):
2 """
3 Mesure le temps d'exécution d'une fonction.
4 """
5 def wrapper(*args, **kwargs):
6 start_time = time.time()
7 func(*args, **kwargs)
8 end_time = time.time()
9 print("Durée d'exécution : {:1.3}s".format(end_time - start_time))
10
11 return wrapper
Nous avons défini deux arguments dans le wrapper
.
À lire aussi : découvrez notre formation MLOps
*args
permet de spécifier des paramètres positionnels (selon leur position lors de l'appel de la fonction).**kwargs
permet de spécifier des paramètres nommés (de la forme param=valeur
).Ces arguments sont ré-utilisés lors de l'appel de la fonction func
.
Ainsi, en exécutant pause(2)
, le paramètre 2 sera envoyé directement à la pause pause
par l'intermédiaire du wrapper
.
1@timing
2def pause(t):
3 print("Début ...")
4 time.sleep(t) # Pause de t secondes
5 print("Fin !")
6
7pause(t=2)
Plus aucune difficulté maintenant pour passer des arguments en paramètres avec les décorateurs de fonctions. 🙂
Vous souhaitez vous former au MLOps ?
Articles similaires
20 sept. 2022
Machine Learning
Nada Belaidi
Data Scientist
Lire l'article
12 juil. 2022
Machine Learning
Nada Belaidi
Data Scientist
Lire l'article
4 juil. 2022
Machine Learning
Nada Belaidi
Data Scientist
Lire l'article
60 rue François 1er
75008 Paris
Blent est une plateforme 100% en ligne pour se former aux métiers Tech & Data.
Organisme de formation n°11755985075.
Data Engineering
À propos
Gestion des cookies
© 2023 Blent.ai | Tous droits réservés