2016-10-26 4 views
2

Ich bin verwirrt durch die Interaktion zwischen Python-2-Iteratoren und Ausnahmen.Wie wiederhole ich nach einer Ausnahme?

Insbesondere den folgenden Code angegeben:

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) 

(! Nehmen Sie bitte die oben genannten sind aus meiner Kontrolle), schreibe ich

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 

in der Hoffnung, den vollen Strom zurückzugewinnen generiert von gen_int.

jedoch die Iteration nach der ersten Ausnahme stoppt:

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

Hier gibt es 3 Anrufungen:

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

Die Frage ist: Wie modifiziere ich gen_all so dass gen_test druckt alle ints unter top?

PS. anscheinend funktioniert die Ausnahme in gen_odd als return - es kennzeichnet den Iterator als erschöpft. ist das wirklich der Fall? Gibt es einen Workaround?

+2

können Sie Pass oder in Ihrem try/except – tinySandy

+0

@tinySandy weiter: könnten Sie bitte das konkretisieren? – sds

+0

Mögliches Duplikat von [python catch exception und continue try block] (http://stackoverflow.com/questions/19522990/python-catch-exception-and-continue-try-block) – tinySandy

Antwort

4

Reassign gen_odd() im except Block:

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 

Der Funktionsgenerator gen_odd einmal stoppt, dass ValueError Ausnahme. Sie müssen die Funktion zum Erstellen eines anderen gen-Funktionsobjekts aufrufen, nachdem das vorherige beendet wurde. gen_odd nimmt ab, wo es aufgehört hat, da die erhaltenen Werte von gen_int an das Funktionsobjekt gebunden sind; Staaten werden gerettet, sonst hätte das nicht funktioniert.


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

Dies ist eine großartige Antwort, aber es funktioniert nur, weil 'gen_int' von einem Singleton' gen_int.x' ausgeht, was bedeutet, dass es den Zustand außerhalb des Generators speichert. Es würde nicht für die meisten Generatoren funktionieren, die Ausnahmen auslösen. – tdelaney

+0

@tdelaney Ja, ich dachte, dass die erhaltenen Werte an das Funktionsobjekt gebunden sind, sonst wäre es sehr anders und wahrscheinlich schwieriger gewesen –

Verwandte Themen