2009-09-02 11 views
45

Je tente de décorer une méthode dans une classe mais python lance une erreur. Ma classe ressemble à ceci:Comment décorer une méthode dans une classe?

from pageutils import formatHeader 

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 jette l'erreur suivante

 
self.createHeader() 
TypeError: wrapped() takes no arguments (1 given) 

Où suis-je Goofing?

Répondre

29

Python transmet automatiquement l'instance de classe comme référence. (L'argument self qui est vu dans toutes les méthodes de classe).

Vous pouvez faire:

def formatHeader(fn): 
    def wrapped(self=None): 
     return '<div class="page_header">'+fn(self)+'</div>' 
    return wrapped 
+0

oh ... et « createHeader », vous retournez un tuple. Faites ceci à la place: 'return" En-tête de page "+ self.PageName' – exhuma

+0

techniquement vous pouvez aussi faire' def wrapped (self) ', sauf si vous voulez utiliser le décorateur aussi en dehors d'une classe. Mais alors les fonctions décorées doivent traiter avec soi-même avec élégance! – exhuma

+0

donc 'fn' est le même que' fn (self, ...) 'ou quelle est la bonne façon de penser où soi si? –

48

Vous omettez le paramètre auto qui est présent dans la fonction undecorated (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 voulez décorer, vous pouvez le faire assez général 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 
+16

+1 sur 'def wrapper (* args, ** kw):' –

+1

+1 pour 'from functools import wraps'. Cela a l'avantage supplémentaire d'exposer la docstring à partir de la fonction enveloppée. Il n'y a aucune raison de ne pas l'utiliser! – jorgeh

Questions connexes