2015-02-18 1 views
0

Я пытаюсь написать декоратор в Python, чтобы ограничить количество раз, когда функция вызывается в течение некоторого времени. Я ожидаю, используя это так:Как я могу оценить ограничение функции в Python 2.7 с помощью декоратора?

@ratelimit(seconds=15) 
def foo(): 
    print 'hello' 

start = time.time() 
while time.time() - start < 10: 
    foo() 

> 'hello' 
> 'hello' 

Так декорированное функция может быть вызвана максимум один раз в seconds. С точки зрения его реализации у меня есть, но это не работает, как я не уверен, что правильный способ сохраняться last_call между последующими вызовами:

import time 

def ratelimit(seconds=10): 

    last_call = None # Never call decorated function 
    def decorator(func): 


     def wrapper(*args, **kwargs): 

      if last_call is None or time.time() - last_call > seconds: 
       result = func(*args, **kwargs) 
       last_call = time.time() 
       return result 

      return wraps(func)(wrapper) 

    return decorator 
+0

Это Python 3? Затем используйте 'nonlocal' для обновления свободной переменной типа' last_call'. –

+0

Python 2.7 не имеет нелокальных значений. – nickponline

+0

Да, но, как [один из ответов] (http://stackoverflow.com/a/2009474/846892) в dup, вы можете использовать изменяемый элемент, например list или dict в Python 2, для хранения и обновления таких элементов. Атрибуты функций также должны работать. –

ответ

2

ниже код работает отлично для меня в Python 2.7.

import time 
from functools import wraps 

last_called = dict() # When last called, and with what result 

def ratelimit(seconds=10, timer=time.time): 
    def decorator(func): 
     last_called[func] = None 

     @wraps(func) 
     def wrapper(*args, **kwargs): 
      now = timer() 
      call_data = last_called.get(func, None) 
      if call_data is None or now - call_data[0] >= seconds: 
       result = func(*args, **kwargs) 
       last_called[func] = (now, result) 
      else: 
       result = call_data[1] # Replay rate-limited result 
      return result 
     return wrapper 
    return decorator