Contenu du cours
Techniques d'Optimisation en Python
Techniques d'Optimisation en Python
Mesurer la Performance des Fonctions
Bien que la mesure des extraits de code basés sur des chaînes puisse suffire parfois, cette approche manque de flexibilité. Utiliser timeit
avec des fonctions offre un moyen plus efficace de mesurer les performances, et les décorateurs simplifient le processus de mesure des performances de plusieurs fonctions de manière propre et modulaire.
Utilisation de timeit avec des Fonctions
timeit
peut mesurer les performances des fonctions directement en passant un appelable (c'est-à-dire, une fonction) au lieu d'une chaîne. Cela est plus flexible et lisible que d'utiliser des chaînes, surtout lorsque vous souhaitez évaluer des fonctions complexes.
import timeit import numpy as np # Function to test def generate_squares(): return np.array([x ** 2 for x in range(1000000)]) # Measure time using a callable (function) iterations = 15 execution_time = timeit.timeit(generate_squares, number=iterations) # Calculate average time per run average_time = execution_time / iterations print(f'Average execution time: {average_time:.6f} seconds')
Nous passons generate_squares
comme la fonction (appelable) à chronométrer en utilisant timeit.timeit()
. Comme précédemment, le paramètre number
spécifie le nombre de fois que la fonction doit être exécutée (15
fois). Le temps d'exécution moyen est ensuite calculé en divisant le temps total par le nombre d'exécutions.
Cette méthode est plus propre et plus efficace pour évaluer les performances des fonctions réelles, et elle évite la surcharge d'évaluer du code à partir d'une chaîne.
import timeit import numpy as np code_snippet = 'np.array([x ** 2 for x in range(1000000)])' iterations = 15 execution_time = timeit.timeit(code_snippet, number=iterations) average_time = execution_time / iterations print(f'Average execution time: {average_time:.6f} seconds')
Oups, nous avons obtenu l'erreur suivante : NameError: name 'np' is not defined
. L'erreur se produit parce que timeit.timeit()
exécute le code en isolation, donc il n'a pas accès à numpy
à moins que vous ne l'importiez explicitement dans l'argument setup
:
Utiliser des fonctions est plus propre, réduit les erreurs et ne nécessite pas de gérer les imports externes via une chaîne setup
.
Amélioration de la Mesure de Performance avec les Décorateurs
Appliquer la même logique de chronométrage à plusieurs fonctions est une pratique courante, et un décorateur offre un moyen propre et efficace de l'implémenter sans répéter le code.
Chaque fois qu'une fonction est appelée, elle s'exécute comme d'habitude, mais avec un benchmarking transparent ajouté. Les décorateurs offrent plusieurs avantages : ils améliorent la réutilisabilité en appliquant la même logique à plusieurs fonctions, améliorent la clarté en séparant la logique de chronométrage de la fonctionnalité principale, et permettent la personnalisation, comme l'ajustement du nombre d'itérations ou l'ajout de métriques supplémentaires pour l'analyse des performances.
import timeit # Decorator to time the execution of a function def timeit_decorator(number=1): def decorator(func): def wrapper(*args, **kwargs): # Measure time with timeit total_time = timeit.timeit(lambda: func(*args, **kwargs), number=number) average_time = total_time / number print(f'{func.__name__} executed in {average_time:.6f} seconds (average over {number} runs)') return func(*args, **kwargs) return wrapper return decorator # Function to measure @timeit_decorator(number=30) def generate_squares(): return [x**2 for x in range(1000000)] # Calling the decorated function squares_array = generate_squares()
Désormais, chaque fois que vous appelez une fonction décorée avec @timeit_decorator
, sa performance sera mesurée automatiquement, et les résultats seront affichés.
Merci pour vos commentaires !