gpt4 book ai didi

python - 为什么 Contextmanager 抛出运行时错误 'generator didn' t 在 throw() 之后停止?

转载 作者:太空狗 更新时间:2023-10-29 17:57:08 24 4
gpt4 key购买 nike

在我的 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

最佳答案

with 语句不是循环结构。它不能用于重复执行代码。使用 @contextmanager 创建的上下文管理器应该只 yield 一次。

上下文管理器(基本上)做三件事:

  1. 它在代码块之前运行一些代码。
  2. 它在代码块之后运行一些代码。
  3. 可选地,它会抑制在代码块中引发的异常。

如果你想做这样的事情,你需要重写它,以便将循环移到上下文管理器之外,或者根本没有上下文管理器。

一个选择是编写一个接受回调作为参数的函数,然后在循环中调用回调,就像您当前在上下文管理器中拥有的那样:

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 传递它。 .

关于python - 为什么 Contextmanager 抛出运行时错误 'generator didn' t 在 throw() 之后停止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34775099/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com