2009-09-02 14 views
45

Estoy intentando decorar un método dentro de una clase, pero Python está arrojando un error. Mi clase es el siguiente:¿Cómo decorar un método dentro de una clase?

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 lanza el siguiente error

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

¿Dónde estoy haciendo el tonto?

Respuesta

29

Python automáticamente pasa la instancia de la clase como referencia. (El argumento self que se ve en todos los métodos de clase).

que podría hacer:

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

oh ... y en "createHeader", va a devolver una tupla Haga esto en su lugar: 'return' Page Header "+ self.PageName ' – exhuma

+0

técnicamente también podría hacer' def wrapped (self) ', a menos que desee utilizar el decorador también fuera de una clase. ¡Pero entonces las funciones decoradas deben tratar con 'yo' con gracia! – exhuma

+0

entonces 'fn' es lo mismo que' fn (self, ...) 'o ¿cuál es la forma correcta de pensar en self si? –

48

Usted está omitiendo el parámetro auto que está presente en la función sin decorar (createHeader en su caso).

def formatHeader(fn): 
    from functools import wraps 
    @wraps(fn) 
    def wrapper(self): 
     return '<div class="page_header">'+fn(self)+'</div>' 
    return wrapper 

Si no está seguro acerca de la firma de la función que desea decorar, que puede hacer que sea más bien general de la siguiente manera:

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 en 'def wrapper (* args, ** kw):' –

+1

+1 for 'from functools import wraps'. Esto tiene la ventaja adicional de que expone la cadena de documentos de la función envuelta. ¡No hay razón para no usarlo! – jorgeh

Cuestiones relacionadas