打破生成器循环的优雅方法:GeneratorExit 错误

yln*_*nor 1 python generator break python-3.x

我有一个在生成器上循环的代码。如果第二次迭代到达它,我必须打破该循环。为此,我使用,它在调用该方法时break引发 a 。GeneratorExitGenerator.close()

for page in limit_handled(tweepy.Cursor(..., ..., ...):
    while len(the_list) < 400:
        for status in page:

            def process_status(tweet):
                ...
                ...

            the_list.append(process_status(status))

    break
Run Code Online (Sandbox Code Playgroud)

是否有一种更优雅的方法可以避免此类错误?

Exception ignored in: <generator object limit_handled at 0x000000003AB300A0>
RuntimeError: generator ignored GeneratorExit
Run Code Online (Sandbox Code Playgroud)

我已经看到了这两个问题的答案:如何获取第一个 N... 如何获取下一个 n...但这不是同一个问题。就我而言,Generator使用Cursor. 因此,在每次迭代时它都会处理一个查询。我想在达到至少 400 个状态后停止查询,这可能在第二次或第三次迭代之后发生(查询通常返回 200 行,但也可以更少)。此处不能选择对生成器进行切片。避免处理所有查询(总共 16 个,大约 16*200=3200 个状态)正是我想通过在返回 400 个状态后破坏代码来避免的。

编辑:为了更好地理解,这里是我的生成器的代码:

def limit_handled(cursor):
    global user_timeline_remaining
    while True:
        if user_timeline_remaining>1:
            try:
                yield cursor.next()
            except BaseException as e:
                print('failed_on_CURSOR_NEXT', str(e))
        else:
            time.sleep(5*60)
                try:
                    data = api.rate_limit_status()
                except BaseException as f:
                    print('failed_on_LIMIT_STATUS', str(f))
                user_timeline_remaining = data['remaining_queries']
Run Code Online (Sandbox Code Playgroud)

Mar*_*ers 5

您的生成器会忽略GeneratorExit引发的异常generator.close()。通过捕获BaseException,您实际上使关闭变得不可能,因此您的生成器将产生另一个值(因为代码在异常处理程序后继续返回循环顶部,直到yield再次到达)。这就是您看到异常的原因:

如果生成器产生一个值,则 aRuntimeError被提升。

你真的不应该BaseException在你的代码中陷入困境。捕获特定的异常,或者最多Exception

except Exception a e:
    # ...
Run Code Online (Sandbox Code Playgroud)

这样你就不会捕获GeneratorExit( 的子类BaseException),SystemExitKeyboardInterrupt

如果你觉得你的代码必须 catch SystemExitandKeyboardInterrupt此时,至少except GeneratorExit: return在你的处理程序之前添加一个except BaseException as e: