在运行时向函数对象添加方法

时间:2010-04-17 21:11:32

标签: python function decorator

我之前读过一个问题,询问Python中是否有times方法,允许连续n次调用函数。

每个人都建议for _ in range(n): foo(),但我想尝试使用函数装饰器编写不同的解决方案。

这就是我所拥有的:

def times(self, n, *args, **kwargs):
    for _ in range(n):
        self.__call__(*args, **kwargs)

import new
def repeatable(func):
    func.times = new.instancemethod(times, func, func.__class__)

@repeatable
def threeArgs(one, two, three):
    print one, two, three

threeArgs.times(7, "one", two="rawr", three="foo")

当我运行程序时,我得到以下异常:

Traceback (most recent call last):
  File "", line 244, in run_nodebug
  File "C:\py\repeatable.py", line 24, in 
    threeArgs.times(7, "one", two="rawr", three="foo")
AttributeError: 'NoneType' object has no attribute 'times'

所以我想装饰师不起作用?我该如何解决这个问题?

3 个答案:

答案 0 :(得分:3)

你的装饰者应该返回函数对象:

def repeatable(func):
    func.times = new.instancemethod(times, func, func.__class__)
    return func

现在它什么也没有返回,所以你实际上在无

中改变了三个Arg

这是因为:

@decorator
def func(...):
    ...

或多或少与:

相同
def func(...):
    ....
func = decorator(func)

答案 1 :(得分:1)

您在return func装饰者的末尾遗漏了repeatable声明。

答案 2 :(得分:0)

您是否考虑过不将其添加到特定功能中,而是允许将其与任何功能一起使用?

def times(n, func, *args, **kwds):
  return [func(*args, **kwds) for _ in xrange(n)]

(我正在返回一个返回值列表,但您可以将其写入忽略它们,类似于问题中的for循环。)

然后,在您的版本中,使用:

threeArgs.times(7, "one", two="rawr", three="foo")

您改为使用:

times(7, threeArgs, "one", two="rawr", three="foo")