2016-10-26 28 views
2

我对Python-2迭代器和异常之间的交互感到困惑。如何在异常之后继续迭代?

具体地,给出以下代码:

def gen_int(): 
    if not hasattr(gen_int,"x"): 
     gen_int.x = 0 
    while True: 
     gen_int.x += 1 
     yield gen_int.x 

def gen_odd(): 
    for x in gen_int(): 
     if x % 2: 
      yield x 
     else: 
      raise ValueError("gen_odd",x) 

(!请假设以上是了我的控制),我写

def gen_all(): 
    it = gen_odd() 
    while True: 
     try: 
      yield it.next() 
     except ValueError as exn: 
      print exn 
      func_name, x = exn 
      assert func_name == "gen_odd" 
      yield x 

在恢复全码流的希望由gen_int生成。

然而,迭代第一个异常后停止:

def gen_test(top): 
    for x in gen_all(): 
     print x 
     if x > top: 
      break 

这里有3个调用:

>>> gen_test(20) 
1 
('gen_odd', 2) 
2 
>>> gen_test(20) 
3 
('gen_odd', 4) 
4 
>>> gen_test(20) 
5 
('gen_odd', 6) 
6 

的问题是: 如何修改gen_all使gen_test将打印全部以下整数top

PS。显然,gen_odd中的例外是return - 它将迭代器标记为已耗尽。这是真的吗?有没有解决方法?

+2

可以使用通/或继续在尝试不同的 – tinySandy

+0

@tinySandy:能否请你更具体? – sds

+0

可能重复的[python捕获异常并继续尝试块](http://stackoverflow.com/questions/19522990/python-catch-exception-and-continue-try-block) – tinySandy

回答

4

重新分配gen_odd()except块:

def gen_all(): 
    it = gen_odd() 
    while True: 
     try: 
      yield it.next() 
     except ValueError as exn: 
      print exn 
      func_name, x = exn 
      assert func_name == "gen_odd" 
      yield x 
      it = gen_odd() # here 

发电机功能一旦ValueError引发异常gen_odd停止。你必须回想起前一次停止后创建另一个gen函数对象的功能。 gen_odd从停止的位置开始拾取,因为从gen_int生成的值被绑定到函数对象;状态被保存,否则这不会起作用。


>>> gen_test(5) 
1 
('gen_odd', 2) 
2 
3 
('gen_odd', 4) 
4 
5 
('gen_odd', 6) 
6 
+1

这是一个很好的答案,但它只是起作用,因为'gen_int'由一个singleton'gen_int.x'工作,这意味着它在生成器之外保存状态。对于引发异常的大多数生成器来说,这是行不通的。 – tdelaney

+0

@tdelaney是的,我认为生成的值必然与函数对象绑定,否则它会非常不同,可能更难 –