在我的 utility.py 中,
@contextmanager
def rate_limit_protection(max_tries=3, wait=300):
tries = 0
while max_tries > tries:
try:
yield
break
except FacebookRequestError as e:
pprint.pprint(e)
if e._body['error']['message'] == '(#17) User request limit reached':
print("waiting...")
time.sleep(wait)
tries += 1
在我的 task.py 中我调用:
for date in interval:
with utility.rate_limit_protection():
stats = account.get_insights(params=params)
在给定日期范围内运行任务后,一旦 Facebook 速率限制生效,程序将等待 300 秒,然后失败并出现错误。
File "/Users/kamal/.pyenv/versions/3.4.0/lib/python3.4/contextlib.py", line 78, in __exit__
raise RuntimeError("generator didn't stop")
RuntimeError: generator didn't stop
The with
语句不是循环结构。它不能用于重复执行代码。使用以下命令创建的上下文管理器@contextmanager
应该只yield
once.
上下文管理器(基本上)做了三件事:
- 它在代码块之前运行一些代码。
- 它在代码块之后运行一些代码。
- 或者,它可以抑制代码块内引发的异常。
如果你想做这样的事情,你需要重写它,以便将循环移到上下文管理器之外,或者根本没有上下文管理器。
一种选择是编写一个接受回调作为参数的函数,然后在循环中调用回调,就像您当前在上下文管理器中使用的那样:
def do_rate_protection(callback, max_tries=3):
tries = 0
while max_tries > tries:
try:
callback()
break
except FacebookRequestError as e:
# etc.
然后你可以这样称呼它:
for date in interval:
def callback():
# code
do_rate_protection(callback)
如果回调不需要date
变量,您可以将其移到循环之外,以避免重复重新创建相同的函数(这会浪费资源)。你也可以做date
的一个参数callback()
函数并使用它传递它functools.partial https://docs.python.org/3/library/functools.html#functools.partial.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)