我采取的第一步是创建一个对象,该对象每 t ms 最多可以分发 n 个硬币。
import time
class CoinsDistribution:
"""Object that distribute a maximum of maxCoins every timeLimit ms"""
def __init__(self, maxCoins, timeLimit):
self.maxCoins = maxCoins
self.timeLimit = timeLimit
self.coin = maxCoins
self.time = time.perf_counter()
def getCoin(self):
if self.coin <= 0 and not self.restock():
return False
self.coin -= 1
return True
def restock(self):
t = time.perf_counter()
if (t - self.time) * 1000 < self.timeLimit:
return False
self.coin = self.maxCoins
self.time = t
return True
现在我们需要一种强制函数只有在他们可以获得硬币时才被调用的方法。为此,我们可以编写一个可以这样使用的装饰器函数:
@limitCalls(callLimit=1, timeLimit=1000)
def uniqFunctionRequestingServer1():
return 'response from s1'
但有时,多个函数调用请求同一个服务器,所以我们希望它们从同一个 CoinsDistribution 对象中获取硬币。因此,装饰器的另一种用途是提供 CoinsDistribution 对象:
server_2_limit = CoinsDistribution(3, 1000)
@limitCalls(server_2_limit)
def sendRequestToServer2():
return 'it worked !!'
@limitCalls(server_2_limit)
def sendAnOtherRequestToServer2():
return 'it worked too !!'
我们现在必须创建装饰器,它可以采用 CoinsDistribution 对象或足够的数据来创建新的。
import functools
def limitCalls(obj=None, *, callLimit=100, timeLimit=1000):
if obj is None:
obj = CoinsDistribution(callLimit, timeLimit)
def limit_decorator(func):
@functools.wraps(func)
def limit_wrapper(*args, **kwargs):
if obj.getCoin():
return func(*args, **kwargs)
return 'limit reached, please wait'
return limit_wrapper
return limit_decorator
它完成了!现在,您可以限制您使用的任何 API 的调用次数,并且如果您必须管理大量 CoinsDistribution 对象(针对不同的 API 端点或不同的 API),您可以构建一个字典来跟踪您的 CoinsDistribution 对象。
注意:这里我选择在没有可用硬币的情况下返回错误消息。您应该根据您的需要调整此行为。