动态传递参数以起作用

时间:2014-06-12 23:03:42

标签: python

我需要跟踪调用集合中每个函数的次数。如果函数在x秒内被调用超过n次,我的程序需要暂停,之后重置该函数的计数。

我的函数调用可能如下所示:

a(1)

b(1,param2=2, param3=3)

c(1,param3=3)

我最好的想法是让包装函数跟踪所有限制。像

这样的东西
def wrapper(function, function_params,x,n):
    if not hasattr(wrapper, "function_dict"):
        wrapper.function_dict = {}
    if function not in wrapper.function_dict.keys():
        wrapper.function_dict[function] = {
            remaining = x, expires = time.time() + n
            }

    remaining = wrapper.function_dict[function]['remaining']
    expires = wrapper.function_dict[function]['expires']

    if remaining == 0:
        time.sleep(expires - time.time())
        wrapper.function_dict[function] = {
            remaining = x, expires = time.time() + n
            }

    results = ????? # call function, this is what I don't know how to do
        wrapper.function_dict[function]['remaining'] -= 1

我的问题是,如何处理函数的参数?我不确定如何确切地说可能存在可变数量的参数,并且可能会命名一些参数。例如,c的函数定义可能是:

def c(param1,param2=2, param3=3):
    return param1 + param2 + param3

但我可能只需要使用param1param3来调用它。

我有正确的一般方法吗?这感觉就像我可以通过**运算符完成的事情,但我仍然坚持如何继续进行。

2 个答案:

答案 0 :(得分:4)

编写装饰器,并使用 splat 运算符处理任意参数。

示例:

def pause_wrapper(x, n):
    def decorator(f):
        config = [x, time.time()+n]
        def wrapped(*args, **kwargs):
            if config[0] == 0:
                time.sleep(config[1] - time.time())
                config = [x, time.time() + n]

            return f(*args, **kwargs)
        return wrapped
    return decorator

和用法:

@pause_wrapper(x, n)
def function(a, b, c):
    ...

*args**kwargs被非正式地称为“splat”参数。采用*args, **kwargs的函数接收元组args中的所有位置参数以及字典kwargs中的所有关键字参数。 (除了splats之外你还可以有其他参数,在这种情况下,splats会吸收所有未发送给命名参数的参数。)

传递*args**kwargs会产生相反的效果,将args的内容作为额外的位置参数传递,将kwargs作为关键字参数传递。

使用两者允许您处理任何一组参数,允许您进行透明包装(如此示例)。

答案 1 :(得分:0)

这基本上是为

制作的装饰器
from collections import defaultdict
class counted:
     calls = defaultdict(int)
     def __init__(self,x,n):
         self.x = x
         self.n = n
     def __call__(self,fn,*args,**kwargs):
         results = fn(*args,**kwargs)
         calls[fn.__name__] += 1
         #do something with the count ...


 @counted(3,9)
 def functionWhatever(arg1,arg2,arg3,**kwargs):
      return "55"

 functionWhatever(1,2,3,something=5)