Magazine

python et les décorateurs

Publié le 29 avril 2008 par Mikebrant

Boules, guirlandes et compagnie

Vous trouvez votre code trop moche ?  Vous voudriez faire de votre .py une oeuvre d'art ?
Et bien les décorateurs sont là ! Enfin ils servent pas à ca, mais presque.

En gros, un décorateur est une fonction qui prend en paramètre votre fonction et qui retourne le résultat( la fonction modifée) .
Et à quoi ca sert ?
Et bah tout simplement à effectuer des opérations sur notre fonction à son initialisation.

Un bon petit exemple connu:

#-*- coding:Utf-8 -*-
class MaClasse:
    
   __instance=None#notre attribut privé, de classe
   __incrementeMoi=0
    
   @classmethod
   def getInstance(cls):
   """ singleton """
   if not isinstance(cls.__instance,cls):
   #si '__instance' n'est pas le type de notre classe
   cls.__instance=cls()
   #on instancie notre classe
   return cls.__instance
   #et on retourne notre __instance,qui maintenant est du type de notre classe
    
    
    
   def __init__(self):
   """à l'initialisation"""
   self.hop="je suis un singleton, et alors ?"
   MaClasse.__incrementeMoi+=+1    
    
   @classmethod
   def  disMoiTout(self):
   """ va retourner le nombre d'instances de MaClasse"""
   return MaClasse.__incrementeMoi
if __name__=='__main__':
   un=MaClasse.getInstance()
   deux=MaClasse.getInstance()
   trois=MaClasse.getInstance()
   print MaClasse.disMoiTout()

Je vous ai même fait cadeau d'un singleton, elle est pas belle la vie ?
Je n'expliquerai pas le principe du singleton, lisez donc mes fabuleux commentaires, ca devrait suffir.

Ici, j'ai voulu vous montrer que le decorateur @classmethod fait de la méthode à laquelle je l'applique une méthode de classe.

Maintenant on va voir des choses un peu plus intéressantes ....
Non On ne va pas voir des photos de jolies demoiselles mais plutôt comment on crée un décorateur....qui dit mieux ?

Il suffit donc de créer une fonction (ou méthode, je précise on sait jamais si quelques âmes perdues se balladent ici) ,que l'on appellera monDecorateur, qui prend en argument maFonction et qui retourne  donc maFonction modifiée.
Ensuite, on place @monDecorateur au dessus de maFonction.

Allez, place à des fabuleux exemples de moi (évidemment, on rit on chante sur des accords qu'on aimait temps, mais pas comme avant).

avec maFonction sans argument :

#-*- coding:Utf-8 -*-
def monDecorateur(maFonction):
   print("Je passe d'abord par là")
   maFonction.ola=("monDecorateur peut même ajouter des variables à ma fonction")
   return maFonction  
@monDecorateur
def maFonction():
   print ("Je passe ensuite par là")
   print maFonction.ola
hop=maFonction()

Ici,
on commence d'abord par éxécuter monDecorateur .
On affiche donc "je passe d'abord par là".
Ensuite on ajoute à maFonction un attribut : ola .
Enfin on retourne maFonction, donc on rentre dans cette dernière et on affiche les deux derniers print.

On va voir maintenant un exemple avec maFonction qui contient cette fois des arguments.
Dans ce cas, il va falloir imbriquer une autre fonction dans monDecorateur qui contiendra les arguments de maFonction.

#-*- coding:Utf-8 -*-
def monDecorateur(maFonction):
   def fonction(arg1,arg2):
   arg1=arg1.upper()
   arg2=arg2.upper()
   return maFonction(arg1,arg2)  
   return fonction
@monDecorateur
def maFonction(monArgument,monAutreArgument):
   return monArgument == monAutreArgument
print maFonction('QuI','qui')

Ici,
c'est un peu plus compliqué.

A l'initialisation de maFonction(monArgument,monAutreArgument) ,on lance donc tout d'abord monDecorateur(maFonction) .
monDecorateur fait une seule chose: il retourne fonction .

Et c'est à ce moment que l'on rentre dans fonction et pas avant  (j'ai bien mis 10 minutes avant de remarquer...donc je le souligne) .

Notre fonction(arg1,arg2) contient en paramètres ceux de maFonction, on a donc : arg1,arg2 = monArgument,monAutreArgument .
fonction va mette en majuscule ses arguments et retourner maFonction, contenant alors les arguments modifiés .

Maintenant on va voir,que l'on peut mettre des arguments à nos décorateurs.
Vous avez donc compris, on va devoir encore imbriquer.

#-*- coding:Utf-8 -*-
def monDecorateur(arg):
  
   def deco(maFonction):
   def fonction(arg1,arg2):
   if type(arg1)==arg and type(arg2)==arg:
   arg1=arg1.upper()
   arg2=arg2.upper()
   return maFonction(arg1,arg2)
   else:
   raise ValueError("Il faut des chaines en paramètres !")
   return fonction
   return deco
  
@monDecorateur(str)
def maFonction(monArgument,monAutreArgument):
   return monArgument == monAutreArgument
print maFonction('a','A')

Ici (ca fait beaucoup de 'ici' ),
on ajoute à  monDecorateur un argument: arg .
monDecorateur retourne deco .

deco est une fonction, mais si vous regardez bien vous verrez que c'est aussi un decorateur (cf l'exemple juste avant) , en effet si monDecorateur prend des arguments il doit retourner un decorateur. Enfin d'un notre côté on s'en fou .
deco, lui aussi ne fait rien à part retourner fonction .

fonction a la même utilité que dans l'exemple au dessus, sauf que cette fois il met en majuscule les éléments si et seulement s'ils sont du même type que arg, l'argument de  monDecorateur.

Voilà, ce billet est terminé, je vais pouvoir enfin aller me coucher.

A noter que l'on peut aussi définir un décorateur comme classe , si ca vous intéresse, je pourrais faire un article dessus.


Retour à La Une de Logo Paperblog

A propos de l’auteur


Mikebrant 9 partages Voir son profil
Voir son blog

l'auteur n'a pas encore renseigné son compte l'auteur n'a pas encore renseigné son compte

Dossier Paperblog