在生成器中捕获异常时保持try block较小

时间:2012-11-23 13:40:39

标签: python exception generator except

当我必须捕获可能在生成器中发生的异常时,如何使try块尽可能小?

典型情况如下:

for i in g():
  process(i)

如果g()可以引发我需要捕获的异常,第一种方法是:

try:
  for i in g():
    process(i)
except SomeException as e:
  pass  # handle exception ...

但如果SomeException中出现process(i),这也会抓住try: for i in g(): except SomeException as e: pass # handle exception ... process(i) (这是我不想要的)。

是否有处理这种情况的标准方法?某种模式?

我正在寻找的是这样的:

{{1}}

(但这当然是句法废话。)

4 个答案:

答案 0 :(得分:3)

您可以转换内部块中发生的异常:

class InnerException(Exception):
  pass

try:
  for i in g():
    try:
      process(i)
    except Exception as ex:
      raise InnerException(ex)
except InnerException as ex:
  raise ex.args[0]
except SomeException as e:
  pass  # handle exception ...

另一个选择是编写一个包装g的本地生成器:

def safe_g():
  try:
    for i in g():
      yield i
  except SomeException as e:
    pass  # handle exception ...
for i in safe_g():
  process(i)

答案 1 :(得分:2)

这种直接的方法似乎是打开for构造(这使得不可能仅仅在生成器中捕获异常,因为它的语法)到它的组件中。

gen = g()
while True:
  try:
    i = gen.next()
  except StopIteration:
    break
  process(i)

现在我们可以将我们预期的异常添加到try块:

gen = g()
while True:
  try:
    i = gen.next()
  except StopIteration:
    break
  except SomeException as e:
    pass  # handle exception ...
    break
  process(i)

那(除了地狱之外的丑陋)有缺点吗?还有更多:有更好的解决方案吗?

(我不会接受我自己的答案,因为它很难看,但也许其他人喜欢并赞成它。)

答案 2 :(得分:1)

在您的生成器中引发一种不同类型的异常,您将能够区分它。

class GeneratorError(Exception):
    pass

def g():
    try:
        yield <smth>
    except:
        raise GeneratorError

try:
  for i in g():
    process(i)
except GeneratorError:
    pass  # handle generator error
except SomeException as e:
  pass  # handle exception .

答案 3 :(得分:0)

我不知道,如果它有效。您可以将g()评估为列表。我无法测试它,因为我没有一个抛出异常的迭代器。

try:
    glist = list(g())
except SomeException as e:
    pass  # handle exception ...
for i in glist:
    process(i)