2011-08-03 17 views
7

कुछ नेस्टेड छोरों से बाहर तोड़ करने के कई तरीकेइटरेटर के बाहर से पाश के लिए करने के लिए भेजा जा रहा है StopIteration

वे इस प्रकार हैं:

1) को तोड़ने के लिए जारी उपयोग करने के लिए

for x in xrange(10): 
    for y in xrange(10): 
     print x*y 
     if x*y > 50: 
      break 
    else: 
     continue # only executed if break was not used 
    break 

2)

def foo(): 
    for x in range(10): 
     for y in range(10): 
      print x*y 
      if x*y > 50: 
       return 
foo() 

3) विशेष अपवाद उपयोग करने के लिए वापसी का उपयोग करने के

class BreakIt(Exception): pass 

try: 
    for x in range(10): 
     for y in range(10): 
      print x*y 
      if x*y > 50: 
       raise BreakIt 
except BreakIt: 
    pass 

मैंने कुछ सोचा था कि ऐसा करने का कोई और तरीका हो सकता है। यह बाहरी लूप पर सीधे भेजे गए स्टॉपइटरेशन अपवाद का उपयोग कर रहा है। मैं इस कोड

it = iter(range(10)) 
for i in it: 
    for j in range(10): 
     if i*j == 20: 
      raise StopIteration 

दुर्भाग्य से, StopIteration किसी के लिए लूप द्वारा पकड़ा नहीं किया गया था लिखा था और है कि कोड एक बदसूरत Traceback का उत्पादन किया। मुझे लगता है कि ऐसा इसलिए है क्योंकि StopIteration को इटरेटर के अंदर से भेजा नहीं गया था। (यह मेरा अनुमान है, मुझे इसके बारे में निश्चित नहीं है)।

क्या कोई तरीका है कि मैं बाहरी लूप को स्टॉपइटरेशन भेज सकता हूं?

धन्यवाद!

उत्तर

4

कुछ आप coroutines साथ कुछ इस तरह कर सकते हैं:

def stoppable_iter(iterable): 
    it = iter(iterable) 
    for v in it: 
     x = yield v 
     if x: 
      yield 
      return 

और फिर इस तरह इसका इस्तेमाल:

it = stoppable_iter(range(10)) 
for i in it: 
    for j in range(10): 
     print i, j 
     if i*j == 20: 
      it.send(StopIteration) # or any value that evaluates as True 
      break 

और यह कैसे काम करता है की एक संक्षिप्त उदाहरण:

>>> t = stoppable_iter(range(10)) 
>>> t.next() 
0 
>>> t.next() 
1 
>>> t.send(StopIteration) 
>>> t.next() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
+0

कृपया, क्या आप समझा सकते हैं, soppable_iter कैसे काम करता है? मुझे लगता है कि अगर एक्स: ... – ovgolovin

+0

यह वास्तव में चालाक है और मैंने प्रदान किए गए वर्ग संस्करण से बहुत छोटा है! – kindall

+0

मुझे लगता है कि मुझे कोरआउट पर नजदीक दिखने की ज़रूरत है, क्योंकि इसके बारे में मेरे वर्तमान ज्ञान के साथ मैं समझ नहीं सकता कि स्टॉपपैबल_टर में एल्गोरिदम क्या करता है। – ovgolovin

1

मुझे लगता है कि क्योंकि StopIteration इटरेटर it के अंदर से नहीं भेजा गया था यह है। (यह मेरा अनुमान है, मुझे इसके बारे में निश्चित नहीं है)।

बिल्कुल सही।

वहाँ किसी भी तरह से है कि मैं अन्य पाश को StopIteration भेज सकते है?

आपके द्वारा परिभाषित अपवाद के बजाय StopIteration का उपयोग करने के अलावा, # 3 के समान तरीका। वैसे भी इसका उपयोग करने के लिए यह एक अच्छा है।

टिप्पणियों में मैंने एक इटरेटर लिखने का उल्लेख किया जिसे अगली बार लूप के माध्यम से स्टॉपइटरेशन बढ़ाने के लिए कहा जा सकता है।

class StoppableIterator(object): 
    def __init__(self, iterable): 
     self._iter = iter(iterable) 
     self._stop = False 
    def __iter__(self): 
     return self 
    def stop(self): 
     self._stop = True 
    def next(self): 
     if self._stop: 
      raise StopIteration 
     return next(self._iter) 

उपयोग::

si = StoppableIterator([2, 3, 5, 7, 11, 13]) 
for i in si: 
    for j in xrange(i): 
     print i, j 
     if j == 7: 
      si.stop() # will break out of outer loop next iteration 
      break  # breaks out of inner loop 
+0

हो सकता है कि वहाँ कुछ जिस तरह से हम StopIteration के साथ टिंकर कर सकते हैं के लिए इसके लिए लूप आवश्यक द्वारा पकड़ा जा रहा है? मुझे लगता है कि यह संभव हो सकता है क्योंकि यदि इटेटरेटर स्टॉपइटरेशन बढ़ाता है, तो फॉर-लूप को छोड़कर अनुभाग को यह निर्धारित करना होता है कि स्टॉपइटरेशन कहां से आता है और इसे प्रसारित करता है यदि यह इसके लिए नहीं है, लेकिन कुछ ऊपरी लूप के लिए। तो, StopIteration ऑब्जेक्ट के कुछ पैरामीटर संपादित करके हम इसे विशिष्ट फॉर-लूप द्वारा पकड़ा जा सकता है। – ovgolovin

+0

नहीं, इसे "यह कहां से आया था" निर्धारित करने की आवश्यकता नहीं है - यह केवल 'अगली()' कॉल के आस-पास 'कोशिश/छोड़कर' रखता है, जो कि इटरेटर से अगला मान प्राप्त करता है। अगर अपवाद पकड़ता है, तो यह जानता है कि यह इटेटरेटर से आया है। अगली बार जब इसे किसी विशेष विधि के नाम से बुलाया जाता है, तो आप 'स्टॉपएक्सप्शन' को बढ़ाने के लिए एक इटरेटर लिख सकते हैं। हालांकि, यह शीर्ष पर लूप से बाहर निकलने में सक्षम होगा, हालांकि। जहां भी आपको आवश्यकता है उसे पकड़ने और इसे स्वयं पकड़ने के लिए बेहतर है। – kindall

+0

ओह। अब मैं इसे देखता हूँ। तो जब हम कुछ लिखते हैं: क्योंकि मैं पुन: प्रयोज्य हूं: #do_sth for-loop iterator की अगली() विधि को सजाने और StopIteration को पकड़ता है। मैं नहीं करता हूं कि अगली बार जब इसे किसी विशेष विधि के नाम से बुलाया जाता है, तो स्टॉपएक्सप्शन को बढ़ाने के लिए मैं एक इटरेटर कैसे लिख सकता हूं, सिर्फ विचार प्राप्त करने में कामयाब नहीं रहा है। – ovgolovin

4

नेस्टेड छोरों आप से तोड़ने के लिए चाहते हैं, के लिए एक और दृष्टिकोण उन्हें संक्षिप्त करने के लिए है यहाँ मैं के बारे में बात कर रहा हूँ बात की तरह है।तो जैसे

for x, y in ((x, y) for x in range(10) for y in range(10)): 
    print x*y 
    if x*y > 50: break 
+0

हाँ। इसे इस तरह से भी लिखा जा सकता है: itertools आयात उत्पाद से >>> उत्पाद में i, j, k (रेंज (5), रेंज (6), रेंज (7)): ... पास मैं बस हूँ दिलचस्पी है कि अगर कोई रास्ता है तो मैं स्टॉपइटरेशन को बदल सकता हूं ताकि इसे विशेष रूप से फॉर-लूप द्वारा पकड़ा जा सके। – ovgolovin

1

आपका उपयोग कर सकते हैं, जो प्रत्येक जनरेटर के बाद से पाइथन 2.5:

कोड पायथन 3.2 में है, लेकिन इसे 2.x में भी काम करना चाहिए।
पायथन 2.x में मैं range के बजाय xrange का उपयोग करूंगा।

outer_loop_iterator = (i for i in range(10)) #we need named generator 
for x in outer_loop_iterator: 
    for y in range(10): 
     print(x*y) 
     if x*y > 50: 
      outer_loop_iterator.close() 
      break #I'm affraid that without this inner loop could still work 
संबंधित मुद्दे