我想写一个装饰器来限制对包装函数的调用次数。比如说,如果我希望包装函数最多被调用 10 次,装饰器应该先执行该函数 10 次,然后它应该返回 None。
这是我想出的:
from functools import wraps
def max_calls(num):
"""Decorator which allows its wrapped function to be called `num` times"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
calls = getattr(wrapper, 'calls', 0)
calls += 1
if calls == num:
return None
setattr(wrapper, 'calls', calls)
return func(*args, **kwargs)
setattr(wrapper, 'calls', 0)
return wrapper
return decorator
然而,这个计数调用正确,当达到限制时返回 None,但是......它不会在程序运行之间重置。也就是说,如果我执行一次程序,计数器达到5,然后重新执行程序,它从5继续。我需要更改什么才能使装饰器正常工作?
请您参考如下方法:
问题是您只维护一组调用计数。但这意味着每个 Flask 请求与所有其他请求共享调用计数。您需要做的是为每个 Flask 请求维护一组单独的调用计数。
来自阅读API documentation似乎完成这项工作的方法是执行以下三个步骤:
创建
flask.Request的子类可以存储您的函数调用计数:import collections import flask class MyRequest(flask.Request): """A subclass of Request that maintains function call counts.""" def __init__(self, *args, **kwargs): super(MyRequest, self).__init__(*args, **kwargs) self.call_counts = collections.defaultdict(int)设置
request_class初始化应用程序时到子类:app = flask.Flask(__name__, request_class=MyRequest, ...)重写您的装饰器以将其计数存储在全局
flask.request中对象:import functools def max_calls(num, default=None): """Decorator which allows its wrapped function to be called at most `num` times per Flask request, but which then returns `default`. """ def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): if flask.request.call_counts[func] == num: return default flask.request.call_counts[func] += 1 return func(*args, **kwargs) return wrapper return decorator
但是写了这么多,如果我不指出你的问题看起来很奇怪,那将是我的失职。为什么要限制Flask请求可以调用一个函数的次数?您是否正在尝试进行某种速率限制?似乎无论您想做什么,都可以使用其他方法做得更好。
