如何在类内装饰方法?

73 投票
3 回答
49934 浏览
提问于 2025-04-15 14:01

我正在尝试给一个类里的方法加装饰器,但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)

我哪里搞错了呢?

3 个回答

2

你也可以在程序运行的时候给方法加装饰,但不能在定义的时候加。这在你无法访问或者不想修改源代码的情况下会很有用,比如说。


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

68

你漏掉了一个叫做self的参数,这个参数在你没有装饰器的函数里是有的(在你的例子中是createHeader)。

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
47

在Python中,当你使用一个类的实例时,它会自动把这个实例作为引用传递给方法。这就是我们在所有实例方法中看到的那个self参数。

你可以这样做:

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

撰写回答