如何为方法创建装饰器

时间:2019-04-10 12:21:12

标签: python python-2.7 decorator

我想装饰一个简单的方法,运行5次:

def do_5(f):
    @wraps(f)
    def wr(*a,**kw):
        i = 0
        while i < 5:
            f(a,kw)
            i += 1
    return wr

class a(object):
    @do_5
    def f(self, x):
        print x

但是,这只会使功能打印{},其中x实际上是1

使用ipdb,我看到self*a的第一个,因此我尝试将包装器更改为

In [37]:     def do_5(f):
    ...:         @wraps(f)
    ...:         def wr(*a,**kw):
    ...:             self, other_args = a[0], a[1:]
    ...:             i = 0
    ...:             while i < 5:
    ...:                 f(self,other_args,kw)
    ...:                  i += 1
    ...:         return wr

In [37]:     def do_5(f):
    ...:         @wraps(f)
    ...:         def wr(*a,**kw):
    ...:             self, other_args = a[0], a[1:]
    ...:             i = 0
    ...:             while i < 5:
    ...:                 self.f(other_args,kw)
    ...:                  i += 1
    ...:         return wr

但得到:

RuntimeError: maximum recursion depth exceeded

TypeError: f() takes exactly 2 arguments (3 given)

分别

我该如何解决?

顺便说一句,我可以像@do_n(f,n)一样动态地修饰这个装饰器,并像这样装饰它(@do_n(100)),而只需使用n而不是5包装器?

2 个答案:

答案 0 :(得分:4)

当您使用参数*a**kw定义包装器时,a是一个元组,kw是一个字典。函数定义中的***是在调用函数时将参数收集到两个参数中的信号。您要将这两个对象传递给f,而不是其中包含参数 containing 。您需要在对包装函数的调用中将其解压缩。在通话中,*** 解包所附的名称。

def do_5(f):
    @wraps(f)
    def wr(*a,**kw):
        i = 0
        while i < 5:
            f(*a, **kw)
            i += 1
    return wr

现在,a().f(3)将输出

3
3
3
3
3

符合预期。

答案 1 :(得分:0)

您需要按原样转发数据,f(*a,**kw),a是一个元组,kw是字典。

from functools import wraps


def do_5(f):
    @wraps(f)
    def wr(*a,**kw):
        i = 0
        while i < 5:
            f(*a,**kw)
            i += 1
    return wr

class a(object):
    @do_5
    def f(self, x):
        print x

b = a()
b.f(1)