web-dev-qa-db-fra.com

Comment décorer une méthode à l'intérieur d'une classe?

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?

51
gath

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
34
exhuma

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
58
krawyoti

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

1
Sibbs Gambling