2016-10-26 54 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是的,我認爲生成的值必然與函數對象綁定,否則它會非常不同,可能更難 –