2025, Oct 16 10:32
Python में नेस्टेड for–while से सही समय पर बाहर निकलना
यह गाइड Python में nested loops के नियंत्रण प्रवाह को सरल करती है: break कहाँ लगाएँ, शर्त कहाँ जाँचें, retries और reset कैसे सँभालें, ताकि for–while कुशल हों.
Python में नेस्टेड लूप्स के बीच नियंत्रण रखना अक्सर इस बात पर निर्भर करता है कि break कहाँ लगाया जाए और कौन‑सी शर्त जाँची जाए। जब आपको किसी ब्लॉक को कई बार आज़माना हो, लक्ष्य शर्त पूरी होते ही जल्दी रुकना हो, और अन्यथा स्टेट रीसेट कर फिर से प्रयास करना हो, तो break की जगह या जाँचों की रचना में छोटी‑सी गलती भी उलझन पैदा कर सकती है। नीचे एक संक्षिप्त मार्गदर्शिका है कि ज़रूरत पड़ने पर nested for और उसे घेरे हुए while से ठीक समय पर कैसे बाहर निकलें।
समस्या का सार
काम यह है कि अंदरूनी लूप को तय संख्या तक दोबारा आज़माया जाए, और जैसे ही लक्ष्य काउंटर सीमा तक पहुँचे, उस inner लूप से तुरंत निकलकर outer लूप की अगली iteration पर बढ़ा जाए। यदि सीमा पूरी नहीं होती, तो कुछ काउंटर रीसेट करके inner लूप को फिर चलाया जाए। अवधारणा तौर पर यह अन्य भाषाओं के repeat जैसा लगता है, पर यहाँ इसे Python के while, for और break से साधना है।
समस्या वाले पैटर्न (उदाहरण हेतु)
नीचे दिया गया खाका उस आम ढाँचे को दिखाता है जिसमें यह उलझन रहती है कि break/continue कहाँ हों और किस स्तर पर कौन‑सी शर्त जाँची जाए। नाम सामान्य रखे गए हैं, तर्क वही है।
def run_process(payload):
    tally1 = 0
    for idx in range(0, 10):
        tally2 = 0
        group_a = alpha[idx]
        group_b = beta[idx]
        limit = len(payload)
        MAX_TRIES = 10
        attempts = 0
        while attempts < MAX_TRIES and tally2 < limit:
            for item in group_a:
                if cond_a == cond_a:
                    random.choice(stuff1, stuff2)
                    if cond_b == cond_b:
                        tally1 += 1
                    if cond_c == cond_c:
                        tally2 += 1
            # अगर tally2 == limit:
            #     OUTER लूप की अगली iteration पर जाओ (break/continue कहाँ करें?)
            # नहीं तो:
            #     INNER लूप दोहराओ (कैसे?)
            #     tally1 -= tally2
            #     tally2 = 0
    return result_marker
असल में हो क्या रहा है
यहाँ नियंत्रण प्रवाह के दो अलग पहलू साफ़‑साफ़ सँभालने हैं। पहला, अगर inner for के भीतर ही सफलता की शर्त पूरी हो जाए (tally2 limit तक पहुँचे), तो बेकार का काम टालने के लिए उसी समय उस for से निकल जाना चाहिए। दूसरा, for खत्म होने के बाद यह तय करना होता है कि क्या अब while से भी बाहर निकलना है। इसके लिए for के बाहर वही शर्त दोबारा जाँचना पड़ती है, क्योंकि break एक ही स्तर के लूप से बाहर निकालता है।
इसी वजह से वही if जाँच दो जगह वाजिब है: एक बार ताकि लक्ष्य मिलते ही inner for रुक जाए, और दूसरी बार for के तुरंत बाद, ताकि तय हो सके कि while के अंदर की कोशिशें भी रोकनी हैं या नहीं। यदि शर्त पूरी नहीं हुई, तो ज़रूरी काउंटर रीसेट करके अगली while iteration में inner लूप फिर चलाया जाता है।
कारगर हल: दो जगह break
पहला तरीका दोनों स्तरों पर साफ़‑साफ़ break लगाता है। लक्ष्य मिलते ही for को पहले ही रोक देता है और फिर तुरंत while से बाहर आ जाता है, ताकि outer for आगे बढ़ सके। अगर लक्ष्य नहीं मिला, तो स्टेट रीसेट कर फिर कोशिश करता है।
def run_process(payload):
    tally1 = 0
    for idx in range(0, 10):
        tally2 = 0
        group_a = alpha[idx]
        group_b = beta[idx]
        limit = len(payload)
        MAX_TRIES = 10
        attempts = 0
        while attempts < MAX_TRIES and tally2 < limit:
            for item in group_a:
                if cond_a == cond_a:
                    random.choice(stuff1, stuff2)
                    if cond_b == cond_b:
                        tally1 += 1
                    if cond_c == cond_c:
                        tally2 += 1
                        if tally2 == limit:
                            break
            if tally2 == limit:
                break
            tally1 -= tally2
            tally2 = 0
    return result_marker
मुख्य बात है उसी शर्त का दोहराव। अंदर की जाँच जैसे ही tally2 limit तक पहुँचता है, for से बाहर निकल जाती है। बाहर की जाँच उसके तुरंत बाद while को भी रोक देती है, और रीसेट वाला भाग स्किप हो जाता है।
विकल्प: एक ही break, बाहर उलटी शर्त
यही व्यवहार for के बाहर शर्त उलटकर भी मिल सकता है। चूँकि while attempts < MAX_TRIES और tally2 < limit स्थिति में tally2 == limit होते ही अपने‑आप समाप्त हो जाएगा, इसलिए बाहर का ब्लॉक केवल तभी चलेगा जब लक्ष्य अभी पूरा न हुआ हो।
def run_process(payload):
    tally1 = 0
    for idx in range(0, 10):
        tally2 = 0
        group_a = alpha[idx]
        group_b = beta[idx]
        limit = len(payload)
        MAX_TRIES = 10
        attempts = 0
        while attempts < MAX_TRIES and tally2 < limit:
            for item in group_a:
                if cond_a == cond_a:
                    random.choice(stuff1, stuff2)
                    if cond_b == cond_b:
                        tally1 += 1
                    if cond_c == cond_c:
                        tally2 += 1
                        if tally2 == limit:
                            break
            if tally2 != limit:
                tally1 -= tally2
                tally2 = 0
    return result_marker
यह रूपांतरण दूसरा break हटाता है: रीसेट वाला भाग केवल तब चलता है जब लक्ष्य अब भी नहीं मिला। जैसे ही tally2 limit तक पहुँचे, while की शर्त झूठी हो जाती है और लूप खुद ही बंद हो जाता है।
यह पैटर्न क्यों मायने रखता है
नेस्टेड लूप तब तक आसान लगते हैं जब तक आपको बिल्कुल सही समय पर बाहर निकलना न हो। for और while का मेल तब स्पष्टता माँगता है कि किस लूप से, कब बाहर आना है। एक ही शर्त को दोनों दायरों में सोच‑समझकर रखना, या बाहर उसे उलट देना, फालतू iterations रोकने, रीसेट लॉजिक में अनचाहे गिरने से बचाने और retries को सीमित व अनुमान योग्य रखने का भरोसेमंद तरीका है। जो भी repeat‑शैली के व्यवहार को मॉडल कर रहा हो, उसके लिए यह संरचना retries को नियंत्रित करने का साफ‑सुथरा उपाय है, जबकि समाप्ति बिंदु स्पष्ट बने रहते हैं।
व्यावहारिक निष्कर्ष
जब inner लूप बीच में ही सफलता की शर्त पूरी कर सकता हो, तो तुरंत break कर दें। inner लूप के बाद वही शर्त फिर जाँचें ताकि तय हो सके कि retry लूप रोकना है या रीसेट करके अगला प्रयास करना है। चाहें तो दूसरी जाँच उलट दें और लक्ष्य मिलते ही while की शर्त को लूप स्वयं बंद करने दें। इससे प्रवाह स्पष्ट रहता है, स्टेट परिवर्तन साफ़ दिखते हैं, और नेस्टेड लूप्स की परस्पर क्रिया सीधी बनी रहती है।
यह लेख StackOverflow के प्रश्न, जिसे user3500717 ने पूछा, और furas के उत्तर पर आधारित है।