动态传递参数给函数

0 投票
2 回答
1583 浏览
提问于 2025-04-18 09:37

我需要记录每个函数被调用的次数。如果某个函数在 n 秒内被调用超过 x 次,我的程序就需要暂停,然后重置这个函数的调用次数。

我的函数调用可能看起来像这样:

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

这基本上就是装饰器的用途。

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)
4

写一个装饰器,并使用星号操作符来处理任意数量的参数。

举个例子:

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通常被称为“星号”参数。一个接受*args, **kwargs的函数,会把所有的位置参数放到一个叫args的元组里,把所有的关键字参数放到一个叫kwargs的字典里。(你可以在这些星号参数之外再加其他参数,这样的话,星号参数就会接收所有没有被命名的参数)。

传递*args**kwargs的效果正好相反,它们会把args里的内容作为额外的位置参数传递,而kwargs里的内容作为关键字参数传递。

同时使用这两者可以让你处理任何一组参数,无论是输入还是输出,这样你就可以做到透明的包装(就像这个例子一样)。

撰写回答