限制Python中的函数调用

j13*_*13r 6 python throttling

我有以下类型的代码,但它很慢,因为report()经常被调用。

import time
import random

def report(values):
    open('report.html', 'w').write(str(values))

values = []

for i in range(10000):
    # some computation
    r = random.random() / 100.
    values.append(r)
    time.sleep(r)
    # report on the current status, but this should not slow things down
    report(values)
Run Code Online (Sandbox Code Playgroud)

在这个说明性代码示例中,我希望报告是最新的(最多 10 年前),因此我想限制该函数。

我可以分叉报告,写入当前时间戳,然后等待该时间段,并使用共享内存时间戳检查报告是否同时被调用。如果是,则终止,如果不是,则写报告。

Python 有没有更优雅的方法?

Mat*_*ttH 6

这是一个装饰器,它将接受一个参数来保护内部函数多长时间,如果调用得太早,则会引发异常。

import time
from functools import partial, wraps

class TooSoon(Exception):
  """Can't be called so soon"""
  pass

class CoolDownDecorator(object):
  def __init__(self,func,interval):
    self.func = func
    self.interval = interval
    self.last_run = 0
  def __get__(self,obj,objtype=None):
    if obj is None:
      return self.func
    return partial(self,obj)
  def __call__(self,*args,**kwargs):
    now = time.time()
    if now - self.last_run < self.interval:
      raise TooSoon("Call after {0} seconds".format(self.last_run + self.interval - now))
    else:
      self.last_run = now
      return self.func(*args,**kwargs)

def CoolDown(interval):
  def applyDecorator(func):
    decorator = CoolDownDecorator(func=func,interval=interval)
    return wraps(func)(decorator)
  return applyDecorator
Run Code Online (Sandbox Code Playgroud)

然后:

>>> @CoolDown(10)
... def demo():
...   print "demo called"
...
>>>
>>> for i in range(12):
...   try:
...     demo()
...   except TooSoon, exc:
...     print exc
...   time.sleep(1)
...
demo called
Call after 8.99891519547 seconds
Call after 7.99776816368 seconds
Call after 6.99661898613 seconds
Call after 5.99548196793 seconds
Call after 4.9943420887 seconds
Call after 3.99319410324 seconds
Call after 2.99203896523 seconds
Call after 1.99091005325 seconds
Call after 0.990563154221 seconds
demo called
Call after 8.99888515472 seconds
Run Code Online (Sandbox Code Playgroud)