【问题标题】:How to determine whether the for loop exited with an exception or break from inside iterator如何确定 for 循环是否以异常退出或从迭代器内部中断
【发布时间】:2018-11-13 06:58:37
【问题描述】:

我正在尝试在我的生成器中进行清理,但前提是循环体引发了异常,而不是使用 break 退出:

def f():
  for v in [1,2,99,4]:
    try:
      yield v
    except GeneratorExit:
      # how to determine whether generator exited via an exception?
      print("generator exited")
      raise

但是,我还没有找到一种方法来区分迭代器中的breakexception

即以下代码

for v in f():
  if v == 99:
    break

将输出:

generator exited

还有这段代码

for v in f():
  if v == 99:
    raise Exception("boom")

将输出:

 generator exited
 ---------------------------------------------------------------------------
 Exception: boom

所以从生成器的外部来看,差异是可以观察到的,但是我找不到在生成器主体内部观察到这一点的方法f()

【问题讨论】:

  • 如果您创建Minimal, Complete, and Verifiable 示例,您将获得更多更好的答案。尤其要确保输入和预期的测试数据是完整的(不是伪数据),并且可以很容易地剪切和粘贴到编辑器中,以便测试建议的解决方案。
  • 所以区别在于生成的是哪个值。 IE:从示例中value == 99 你为什么/如何期望生成器本身在这里识别差异?
  • 不同之处在于屈服体对值的反应。 IE。我的清理行为需要与生成器的退出是有意的还是异常的不同
  • 我的直觉告诉我这是不可能的。你的异常被捕获并变成了一个GeneratorExit,它不包含第一个异常的属性(例如e.args)。看来您需要修改源代码以保存 GeneratorExit 异常中的第一个异常的属性。

标签: python-3.x generator yield


【解决方案1】:

也许,这有帮助?

def f():
    for v in [1,2,99,4]:
        try:
            if v == 99:
                raise Exception('Boom!')
            yield v
        except:
            print("generator exited")
        else:
            print("generator not exited")

for value in f():
    print(value)

================================================ ========================

可能,我仍然不明白这个问题。无论如何,这是我的第二次尝试:

import sys

class MyException(Exception):
    pass

def f():
    a = input('Break, except, loop, or quit (b/e/l/q)? ' ).strip().lower()
    if a == 'q':
        sys.exit()
    if a == 'l':
        pass    # just the normal loop
    for v in [1, 2, 99, 4]:
        if a == 'b':
            break
        try:
            if a == 'e':
                raise MyException
            yield v
        except MyException:
            print('Inside Generator: MyException')
            return
    else:
        print('Inside Generator: loop terminated!')
        return
    print('Inside Generator: break')

for value in f():
    print(value)

【讨论】:

  • v==99 只是为了说明迭代器内部的行为。它不知道什么值可能导致循环体抛出异常,但如果 for 循环有意退出或由于错误而退出,则需要进行不同的清理。
  • @Arne Claassen:抱歉!我似乎不明白你的问题。我的代码只是一个例子。如果您知道可能的异常,您可以在 except 部分捕获并处理它们。只有在没有异常的情况下,else 部分才会变为活动状态。这样,您应该能够确定循环是否正常终止。
  • 这就是问题所在。异常永远不会出现在收益周围的异常中。生成器在循环退出时引发的 GeneratorExit 隐藏了它
猜你喜欢
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2015-11-23
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
相关资源
最近更新 更多