2010-10-22 13 views
12

मैं हाल ही में कुछ आश्चर्यजनक व्यवहार भर में अजगर जनरेटर में आया:अजगर जनरेटर, 'coroutine' में गैर निगलने अपवाद

class YieldOne: 
    def __iter__(self): 
    try: 
     yield 1 
    except: 
     print '*Excepted Successfully*' 
     # raise 

for i in YieldOne(): 
    raise Exception('test exception') 

कौन सा उत्पादन देता है:

*Excepted Successfully* 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
Exception: test exception 

मैं (सुखद) था हैरान कि *Excepted Successfully* मुद्रित हो गया, जैसा कि मैं चाहता था, लेकिन यह भी हैरान हुआ कि अपवाद अभी भी शीर्ष स्तर तक फैल गया है। मुझे मनाया गया व्यवहार प्राप्त करने के लिए raise कीवर्ड का उपयोग करने की उम्मीद थी (इस उदाहरण में टिप्पणी की गई)।

क्या कोई यह समझा सकता है कि यह कार्यक्षमता क्यों काम करती है, और जेनरेटर में except अपवाद को क्यों निगलता है?

क्या यह पाइथन में एकमात्र उदाहरण है जहां except कोई अपवाद निगलता नहीं है?

उत्तर

14

आपका कोड ऐसा नहीं करता है जो आपको लगता है कि यह करता है। आप इस तरह के कोरआउटिन में अपवाद नहीं उठा सकते हैं। इसके बजाय आप GeneratorExit अपवाद को पकड़ रहे हैं। देखें जब आप एक अलग अपवाद का उपयोग क्या होता है:

class YieldOne: 
    def __iter__(self): 
    try: 
     yield 1 
    except RuntimeError: 
     print "you won't see this" 
    except GeneratorExit: 
     print 'this is what you saw before' 
     # raise 

for i in YieldOne(): 
    raise RuntimeError 

इस के रूप में अभी भी upvotes हो जाता है, आपके द्वारा एक जनरेटर में एक अपवाद बढ़ा है:

class YieldOne: 
    def __iter__(self): 
    try: 
     yield 1 
    except Exception as e: 
     print "Got a", repr(e) 
     yield 2 
     # raise 

gen = iter(YieldOne()) 

for row in gen: 
    print row # we are at `yield 1` 
    print gen.throw(Exception) # throw there and go to `yield 2` 

generator.throw के लिये दस्तावेज देखें।

+0

आह, अब यह समझ में आता है। मैं मूल रूप से जनरेटर को 'ओवर' को बढ़ावा देने के अपवाद की अपेक्षा नहीं करता था। – EoghanM

+0

+1 बहुत दिलचस्प है! 'Generator.throw' चाल को प्रकाशित करने के लिए – rubik

+0

+1! – EoghanM

6

संपादित करें: THC4k ने क्या कहा।

>>> def Gen(): 
...  try: 
...    yield 1 
...  except Exception: 
...    print "Excepted." 
... 
>>> foo = Gen() 
>>> next(foo) 
1 
>>> foo.throw(Exception()) 
Excepted. 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 

आप पाएंगे कि आप शीर्ष स्तर पर एक StopIteration पाने पर ध्यान देंगे:

तुम सच में एक जनरेटर के अंदर एक मनमाना अपवाद को बढ़ाने के लिए चाहते हैं, throw विधि का उपयोग करें। ये जनरेटर द्वारा उठाए जाते हैं जो तत्वों से बाहर निकलते हैं; वे आमतौर पर for लूप द्वारा निगल जाते हैं लेकिन इस मामले में हमने जनरेटर को अपवाद बढ़ाया ताकि लूप उन्हें नोटिस न करे।