web-dev-qa-db-ja.com

クラス内のメソッドを装飾する方法は?

クラス内のメソッドを装飾しようとしていますが、pythonがエラーをスローしています。私のクラスは次のようになります。

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は次のエラーをスローします

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

どこへ行こうかな?

51
gath

Pythonは自動的にクラスインスタンスを参照として渡します。 (すべてのクラスメソッドで見られるself引数)。

あなたがすることができます:

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

装飾されていない関数(あなたの場合はcreateHeader)に存在するselfパラメータを省略しています。

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

装飾する関数のシグネチャがわからない場合は、次のようにかなり一般的にすることができます。

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

実行時にメソッドを装飾することもできますが、定義時に装飾することはできません。これは、たとえば、ソースコードへのアクセス権がない場合や編集したくない場合に役立ちます。


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