J'essaie de décorer une méthode à l'intérieur d'une classe mais python génère une erreur. Ma classe ressemble à ceci:
from pageutils import formatHeader
class myPage(object):
def __init__(self):
self.PageName = ''
def createPage(self):
pageHeader = self.createHeader()
@formatHeader #<----- decorator
def createHeader(self):
return "Page Header ",self.PageName
if __name__=="__main__":
page = myPage()
page.PageName = 'My Page'
page.createPage()
pageutils.py
:
def formatHeader(fn):
def wrapped():
return '<div class="page_header">'+fn()+'</div>'
return wrapped
Python lève l'erreur suivante
self.createHeader()
TypeError: wrapped() takes no arguments (1 given)
Où suis-je en train de gaffer?
Python passe automatiquement l'instance de classe comme référence. (L'argument self
qui est vu dans toutes les méthodes de classe).
Vous pourriez faire:
def formatHeader(fn):
def wrapped(self=None):
return '<div class="page_header">'+fn(self)+'</div>'
return wrapped
Vous omettez le paramètre self qui est présent dans la fonction non décorée (createHeader dans votre cas).
def formatHeader(fn):
from functools import wraps
@wraps(fn)
def wrapper(self):
return '<div class="page_header">'+fn(self)+'</div>'
return wrapper
Si vous n'êtes pas sûr de la signature de la fonction que vous souhaitez décorer, vous pouvez la rendre plutôt générale comme suit:
def formatHeader(fn):
from functools import wraps
@wraps(fn)
def wrapper(*args, **kw):
return '<div class="page_header">'+fn(*args, **kw)+'</div>'
return wrapper
Vous pouvez également décorer la méthode lors de l'exécution, mais pas au moment de la définition. Cela peut être utile dans le cas où vous n'avez pas accès ou ne souhaitez pas modifier le code source, par exemple.
In [1]: class Toy():
...: def __init__(self):
...: return
...: def shout(self, s):
...: print(s)
...:
In [2]: def decor(fn):
...: def wrapper(*args):
...: print("I'm decorated")
...: return fn(*args)
...: return wrapper
...:
In [4]:
In [4]: a=Toy()
In [5]: a.shout('sa')
sa
In [6]: a.shout=decor(a.shout)
In [7]: a.shout('sa')
I'm decorated
sa