Outils pour utilisateurs

Outils du site


decorateurs_compteur

Un décorateur pour compter les appels et les temps d'exécution des fonctions et des méthodes

Objectif

Pendant le développement, il est souvent utile de savoir combien de fois une fonction ou une méthode est appelée, ainsi que de connaitre les durées des traitements.

Certains outils de développement peuvent donner des infos comme ça, mais il est facile de fabriquer son propre outil en Python: c'est l'objet de cette page.

Pour cela, on utilisera les décorateurs, qui “enveloppent” les fonctions et méthodes décorées en permettant d'intervenir avant et après les appels.

Module proposé

Comme il faudra bien conserver les informations entre 2 appels, on va fabriquer un décorateur sous forme de classe, mais sans passage d'arguments.

Voilà le code proposé qu'on va placer dans un fichier appelé, par exemple, libdeco.py, et qu'on utilisera comme un module:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Python 2.7 et 3.2
 
import functools, types
import time
 
#############################################################################
class compteur(object):
    """ decorateur pour compter le nombre d'appels et le temps d'exécution.
        => valable pour décorer des fonctions ou des méthodes de classe
     """
 
    def __init__(self, fonc):
        """initialisation du décorateur"""
        self.fonc = fonc
        self.comptappel = 0 # compteur d'appels
        self.tempsexec = 0 # pour stocker les temps d'exécution
        # pour que les fonctions décorées gardent nom et docstring:
        functools.wraps(fonc)(self)
 
    def __get__(self, inst, owner=None):
        """méthode nécessaire pour décorer les méthodes: avoir le bon 'self' """
        return types.MethodType(self, inst)
 
    def __call__(self, *args, **kwargs):
        """ méthode appelée à chaque appel de la fonction décorée """
 
        # instructions avant l'appel de la fonction décorée
        self.comptappel += 1 # incrémentation du compteur d'appels
        temps = time.clock()  # initialisation du compteur de temps
 
        # appel de la fonction décorée
        result = self.fonc(*args, **kwargs)
 
        # instructions après le retour d'appel de la fonction décorée
        self.tempsexec += time.clock()-temps # ajout du temps d'exécution
 
        # fin d'appel
        return result
 
    def resultat(self):
        """retourne le résultat: compteur d'appel et temps moyen d'exécution"""        
        c = self.comptappel
        t = self.tempsexec
        if c==0: 
            tm = 0
        else: 
            tm = t/c
        return c, tm

Ce code fonctionne sans modification sous Python 2.7 et 3.2.

Comme il s'agit d'un outil de développement, il peut être pratique de l'intégrer directement dans le système Python lui-même avec distutils, afin qu'il soit rendu facilement disponible dans tous les projets de développement.

Exemples d'utilisation

Exemple d'utilisation pour des fonctions

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Python 2.7 et 3.2
 
from libdeco import compteur
 
@compteur
def fonction1():
    for i in range(0,1000000):
        x = sin(4.65789321456)
 
@compteur
def fonction2():
    for i in range(0,1000000):
        x = cos(4.65789321456)
    y = fonction1()    
 
# 3 exécutions de fonction1 et 2 de fonction2 (qui appelle fonction1)
fonction1()
fonction1()
fonction2()
fonction1()
fonction2()
 
# affichage des résultats
 
print(fonction1.resultat())
# affiche: (5, 0.19338031069732708)
 
print(fonction2.resultat())
# affiche: (2, 0.38713576021911655)

Exemple d'utilisation pour des méthodes

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Python 2.7 et 3.2
 
from libdeco import compteur
 
from math import *
 
class maclasse(object):
 
    @compteur
    def methode(self):
        for i in range(0,1000000):
            x = cos(4.65789321456)
 
# appels
v = maclasse()
 
# 4 exécutions de la méthode 'methode'
v.methode()
v.methode()
v.methode()
v.methode()
 
# affichage des résultats
 
print(v.methode.resultat())
# affiche: (4, 0.19418323096733464)


Amusez-vous bien!

decorateurs_compteur.txt · Dernière modification: 2012/03/26 07:52 par tyrtamos

Outils de la page