5

当我必须捕获生成器中可能发生的异常时,如何使 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)

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

4

4 回答 4

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)
于 2012-11-23T13:48:17.573 回答
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)

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

(我不会接受我自己的答案,因为它很丑陋,但也许其他人喜欢并支持它。)

于 2012-11-23T14:02:44.617 回答
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 .
于 2012-11-23T13:42:31.490 回答
0

不知道行不行 你可以评估g()成一个列表。我无法测试它,因为我手头没有抛出异常的迭代器。

try:
    glist = list(g())
except SomeException as e:
    pass  # handle exception ...
for i in glist:
    process(i)
于 2012-11-23T13:52:54.413 回答