====== Décorateurs Python ====== Source : http://gillesfabio.com/blog/2010/12/16/python-et-les-decorateurs/ ===== Built-in decorator ===== * **@property** : transforme une fonction en propriété (en gros transforme une fonctionne comme une variable) class C(object): def __init__(self): self._x = None @property def x(self): """I'm the 'x' property.""" return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x #!/usr/bin/env python3 # -*- coding: utf-8 -*- class myclass(object): x = 0 def __init__(self): print('init') self.x = 0 # Methode classique. Ne peux pas être appelée sans être instanciée # myclass().foo(1) # myclass.foo(1) >>> Erreur def foo(self, x): print("Executing foo ({} : {})".format(self, x)) self.x+=x # Pas besoin d'instancier la classe pour l'appeler. A accès aux attributs de la classe qui ne commencent pas par self. A accès aux méthodes qui ne sont pas instanciées (c'est à dire aux methodes qui n'ont pas de self => @classmethod et @staticmethod). # myclass().class_foo(1) >>> Appelle __init__ car on a instancié la classe # myclass.class_foo(1) @classmethod def class_foo(cls, x): print("Executing class_foo ({} : {})".format(cls, x)) cls.x+=x cls.static_foo(1) # Pas besoin d'instancier la classe pour l'appeler. Vu comme une simple fonction. N'a pas accès aux méthodes # myclass().static_foo(1) >>> Appelle __init__ car on a instancié la classe # myclass.static_foo(1) @staticmethod def static_foo(x): print("Executing static_foo ({})".format(x)) x+=1 if __name__ == '__main__': a=myclass() print('x = {}'.format(a.x)) a.foo(1) print('x = {}'.format(a.x)) a.class_foo(1) print('x = {}'.format(a.x)) a.static_foo(1) print('x = {}'.format(a.x)) print('*'*10) try: myclass.foo(1) except Exception as e: print(e) myclass.class_foo(1) myclass.static_foo(1) ===== Sans arguments ===== def decorate(func): def wrapper(*args, **kwargs): # Pré-traitement response = func(*args, **kwargs) # Post-traitement return response wrapper.__doc__ = func.__doc__ wrapper.__name__ = func.__name__ return wrapper Exemple : # -*- coding: utf-8 -*- # Notre décorateur def decorate(func): print u"Je suis dans la fonction 'decorate' et je décore '%s.'" % func.__name__ def wrapper(*args, **kwargs): print u"Je suis dans la fonction 'wrapper' qui accède aux arguments de '%s'." % func.__name__ a = list(args) a.reverse() print u"J'en donne la preuve, je peux les inverser : %s." % ', '.join(a) print u"Exécution de la fonction '%s'." % func.__name__ response = func(*args) print u"Je peux effectuer, ici, un post-traitement." return response return wrapper # Notre fonction décorée @decorate def foobar(*args): print ", ".join(args) # Appel de la fonction foobar("A", "B", "C", "D") ===== Avec arguments ===== def decorate(arg1, arg2, arg3): def decorated(func): def wrapper(*args, **kwargs): # Pré-traitement response = func(*args, **kwargs) # Post-traitement return response return wrapper return decorated def decorate(arg1='default', arg2=None, arg3=None): def decorated(func): def wrapper(*args, **kwargs): # Pré-traitement response = func(*args, **kwargs) # Post-traitement return response return wrapper return decorated @decorate(arg1='my value') def foobar(): pass # MAUVAIS @decorate def foobar(): pass # BON @decorate() def foobar(): pass Exemple : # -*- coding: utf-8 -*- def decorate(arg1, arg2, arg3): print u'Je suis dans la fonction "decorate".' def decorated(func): print u'Je suis dans la fonction "decorated".' def wrapper(*args, **kwargs): print u'Je suis dans la fonction "wrapper".' print u"Les arguments du décorateurs sont : %s, %s, %s." % (arg1, arg2, arg3) print u"Pré-traitement." print u"Exécution de la fonction %s." % func.__name__ response = func(*args, **kwargs) print u"Post-traitement." return response return wrapper return decorated @decorate("Arg 1", "Arg 2", "Arg 3") def foobar(): print u"Je suis foobar, je vous reçois 5 sur 5." foobar()