Skip to content
This page has been auto-translated and may contain errors.View in English

नियंत्रण प्रवाह

docs.scrimba.com

अब तक आपने जो भी प्रोग्राम लिखा है, वह हर बार एक ही तरीके से चलता है: ऊपर से नीचे, एक बार में एक पंक्ति। यह सरल स्क्रिप्ट के लिए काम करता है, लेकिन वास्तविक प्रोग्राम को निर्णय लेने और काम दोहराने की आवश्यकता होती है। एक क्विज को यह जांचना होता है कि उत्तर सही है या नहीं। एक गेम को तब तक चलते रहना होता है जब तक खिलाड़ी जीत या हार न जाए। यह अध्याय आपके प्रोग्राम को शाखा देने और दोहराने का तरीका बताता है।

नियंत्रण प्रवाह आपके प्रोग्राम का पथ तय करता है। शर्तें (if/elif/else) शाखाओं के बीच चयन करती हैं; लूप (while, for) एक ब्लॉक को दोहराते हैं। Python का for एक बार में सूचकांक गिनने के बजाय items को एक-एक करके चलता है, यही वजह है कि यह इतनी सारी चीजों के साथ स्वच्छ रूप से लूप करता है। यह अध्याय बताता है कि प्रत्येक tool का उपयोग कब करें और प्रत्येक से कौन सी गलतियां आमंत्रित होती हैं।

Python आपको तीन नियंत्रण प्रवाह tools देता है: शाखा के लिए if/elif/else, और दोहराने के लिए while और for। एक for लूप एक iterable (कुछ भी जिसे आप एक बार में एक item चला सकते हैं, जैसे list या file) के माध्यम से चलता है और items समाप्त होने पर अपने आप रुक जाता है, इसलिए आप शायद ही कभी index को हाथ से प्रबंधित करते हैं। एक while लूप तब तक चलता रहता है जब तक इसकी शर्त truthy रहती है। break और continue केवल उनके चारों ओर निकटतम लूप को स्पर्श करते हैं, और लूप else clause (बाद में cover किया गया) केवल तभी चलता है जब कोई लूप break के बिना समाप्त होता है। इस अध्याय का बाकी हिस्सा सही चुनने और प्रत्येक के failure modes से बचने के बारे में है।

तुलना

इससे पहले कि आप कोई निर्णय ले सकें, आपको चीजों की तुलना करनी होती है। तुलना operators True या False return करते हैं। जल्दी सही होने वाला सबसे महत्वपूर्ण: = एक मान assign करता है, == यह जांचता है कि क्या दो मान बराबर हैं। इन्हें मिलाना शुरुआती लोगों की सबसे आम गलतियों में से एक है।

तुलना operators एक bool return करते हैं, और Python आपको उन्हें chain करने देता है: 0 < x < 10 का अर्थ है 0 < x and x < 10, जिसे अधिकांश अन्य भाषाएं बाएं-दाएं पढ़ती हैं और गलत हो जाती हैं। Strings character-by-character को dictionary order में compare करते हैं, इसलिए uppercase lowercase से पहले sort होता है। मानों की तुलना के लिए == का उपयोग करें; आप almost never is चाहते हैं, जो एक अलग प्रश्न पूछता है (Deep Dive में cover किया गया है)।

तुलना एक bool return करती है, और वास्तविक code में दो विवरण मायने रखते हैं। पहला, Python chained comparisons को support करता है: a < b < c को a < b and b < c के रूप में पढ़ा जाता है, और मध्य मान b को केवल एक बार evaluate किया जाता है, जो जानने योग्य है यदि यह एक महंगी call है। दूसरा, == यह जांचता है कि क्या दो मान बराबर हैं, जबकि is identity जांचता है (क्या दो नाम memory में बिल्कुल same object को point करते हैं)। वे interchangeable नहीं हैं: मानों की तुलना == से करें, और None, True, और False के लिए is रखें, जहां आप वास्तव में एक-और-केवल object चाहते हैं। strings या numbers पर is reaching करने से ऐसी bugs होती हैं जो छोटे inputs पर pass होती हैं और बड़े inputs पर fail होती हैं।

python
5 > 3     # True
5 < 3     # False
5 == 5    # True   (note: double equals; = is assignment, == is comparison)
5 != 3    # True   ("not equal to")
5 >= 5    # True   ("greater than or equal to")
5 <= 4    # False  ("less than or equal to")

= vs == का अंतर लगभग सभी को जल्दी में confuse करता है। Assignment (=) एक मान store करता है; comparison (==) जांचता है कि क्या दो मान same हैं।

आप strings की भी तुलना कर सकते हैं। Python उन्हें alphabetically, character-by-character compare करता है, जिसे Strings अध्याय अधिक विस्तार से cover करता है:

python
"apple" == "apple"   # True
"apple" < "banana"   # True  (a comes before b)
"apple" == "Apple"   # False (case-sensitive)
Junoतुलना= एक मान store करता है, == जांचता है कि क्या दो मान बराबर हैं। मैं अभी भी थका हुआ होने पर उस एक को double-check करने के लिए slow down करता हूं, इसलिए आप अच्छी कंपनी में हैं अगर यह आपको confuse करता है। Comparisons `True` या `False` return करती हैं, और वे strings पर भी काम करती हैं, alphabetically।
Junoतुलना Comparisons एक `bool` return करती हैं। Chained forms जैसे `0 < x < 10` को `0 < x and x < 10` के रूप में पढ़ा जाता है, जिसे अधिकांश अन्य भाषाएं गलत करती हैं। String comparison Unicode order से होता है, इसलिए यह case-sensitively sort होता है।
Junoतुलना मान के लिए `==` का उपयोग करें, identity के लिए `is`, और `None`, `True`, और `False` तक `is` को रखें। trap है `is` strings या ints पर: यह छोटे inputs पर pass होता है और बड़े inputs पर fail होता है। Chained comparisons मध्य term को एक बार evaluate करते हैं, जब यह महंगा होता है तो handy।

शर्तों को combine करना

and, or, और not comparisons को combine करते हैं। and को दोनों sides को true होना चाहिए। or को कम से कम एक side को true होना चाहिए। not result को flip करता है। ये आपको वास्तविक दुनिया की शर्तों को व्यक्त करने देते हैं जैसे "score passing है AND user active है"।

and और or short-circuit करते हैं: and पहले falsy operand पर रुकता है, or पहले truthy पर रुकता है। वे bare True या False नहीं, वह actual operand return करते हैं, जो कि name or "guest" एक clean fallback प्रदान करने का तरीका है। not हमेशा आपको एक plain bool देता है।

and और or True या False return नहीं करते, वे एक operand return करते हैं। and पहला falsy operand return करता है, या अंतिम एक अगर सभी truthy हैं; or पहला truthy operand return करता है, या अंतिम एक अगर सभी falsy हैं। right side को evaluate नहीं किया जाता एक बार left result decide करता है, और वह short-circuit guarantee (Python जवाब known होने के तुरंत बाद रुकता है) कुछ है जिस पर आप निर्माण करते हैं: user and user.name केवल user.name को पढ़ता है जब user exist करता है, इसलिए यह missing value पर कभी error नहीं करता। flip side एक real failure mode है: अगर right side का एक side effect है जिस पर आप count कर रहे हैं, जैसे एक function जो logs या writes करता है, यह silently कभी नहीं चलता जब left side short-circuit करता है।

python
age = 25
score = 88

age >= 18 and score >= 80    # True  (both must be true)
age < 18 or score >= 80      # True  (at least one must be true)
not age >= 18                # False (flips the result)

and को दोनों sides चाहिए। or को कम से कम एक side चाहिए। not invert करता है।

Junoशर्तों को combine करनाand को दोनों sides true चाहिए, or को कम से कम एक, not answer को flip करता है। यह अधिकांश वास्तविक conditions cover करता है जिसे आप लिखेंगे, जैसे "score passing है and user active है"। Python जवाब know करने के moment को moment रुक जाता है।
Junoशर्तों को combine करनाand पहले falsy value पर रुकता है, or पहले truthy पर, और दोनों bare `True`/`False` नहीं वह actual operand return करते हैं। वह short-circuiting है जब `x and x.method()` safe रहता है `x` empty होने पर।
Junoशर्तों को combine करनाand/or एक operand return करते हैं, एक bool नहीं, और right side को skip किया जाता है एक बार left outcome decide करता है। `user and user.name` जैसे guards पर lean करें। दूसरे edge को देखें: right side पर एक side effect quietly कभी नहीं fires जब यह short-circuit करता है।

Truthy और falsy

Python में हर value का एक boolean interpretation है, भले ही यह True या False न हो। Empty strings, zero, empty lists, और None सभी condition में False की तरह behave करते हैं। बाकी सब True की तरह behave करते हैं। इसका मतलब है if results: जांचता है कि क्या एक list non-empty है बिना if len(results) > 0: लिखे।

Python की falsy values हैं False, 0, 0.0, "", [], (), {}, set(), और None। बाकी सब truthy है, इसलिए एक empty container falsy है और एक non-empty truthy है। वही है जो if results: को idiomatic emptiness check बनाता है: इसे if len(results) > 0: की बजाय लिखें।

जब आप एक object को condition में डालते हैं, Python इसके __bool__ method को call करके एक हां-या-ना answer मांगता है (एक dunder, double-underscore methods में से एक जिसे Python पर्दे के पीछे call करता है)। यदि एक type __bool__ define नहीं करता है, Python __len__ में fallback करता है, इसलिए कुछ भी length zero के साथ false count करता है। standard falsy values False, 0, 0.0, "", empty containers ([], (), {}, set()), और None हैं; बाकी सब truthy है। trap को देखें: if results: false है एक empty list के लिए और None के लिए भी, इसलिए अगर आप specifically "empty" को "not set yet" से अलग करना चाहते हैं, तो if results is None: test करें बजाय truthiness पर relying करने के।

python
# ये सभी condition में False की तरह behave करते हैं:
False, 0, 0.0, "", [], {}, (), None

# बाकी सब True की तरह behave करता है

इसका मतलब है if results: एक natural तरीका है "अगर list non-empty है" कहने का, और if name: जांचता है कि क्या एक string के पास कोई content है।

JunoTruthy और falsy Empty चीजें और zero condition में `False` count करते हैं: `0`, `""`, `[]`, और `None`। बाकी सब `True` count करता है। वही कारण है कि `if results:` "अगर list में कुछ है" के रूप में इतना cleanly पढ़ता है, कोई `len()` नहीं चाहिए।
JunoTruthy और falsy Falsy है `False`, zero, empty strings, empty containers, और `None`; बाकी सब truthy है। तो एक empty list falsy है और एक full one truthy है। वही कारण है कि `if my_list:` एक emptiness check के रूप में काम करता है, कोई `len()` नहीं चाहिए।
JunoTruthy और falsy Conditions `__bool__` call करती हैं, फिर `__len__` अगर वह missing है, इसलिए आपकी अपनी classes उनकी truthiness pick कर सकती हैं। catch है: `if results:` एक empty list को `None` से अलग नहीं कर सकता। जब वह अंतर मायने रखता है, तो `is None` की ओर reach करें।

if / elif / else

if statement एक block of code को केवल चलाता है जब इसकी condition True हो। elif अधिक conditions add करता है अगर पहली false थी तो check करने के लिए। else सब कुछ catch करता है जो किसी condition से match नहीं हुआ। Python बर्स नहीं, indentation का use करता है यह define करने के लिए कि क्या हर block के अंदर belongs है।

if/elif/else conditions को ऊपर से नीचे evaluate करता है और पहली matching block को run करता है। Python indentation (convention से 4 spaces) use करता है block scope define करने के लिए; inconsistent indentation एक SyntaxError है। केवल एक branch चलता है: एक बार condition match करती है, सभी subsequent elif और else को skip किया जाता है।

Python conditions को ऊपर से नीचे check करता है और exactly एक branch चलाता है: पहला जिसकी condition truthy है, या else अगर कोई match नहीं हुआ। हर condition को lazily evaluate किया जाता है, meaning Python इसे केवल test करता है अगर हर condition इसके ऊपर false थी, इसलिए order logic का हिस्सा है। सबसे सस्ता या सबसे likely test पहले डालें, और overlapping ranges को order करें ताकि tighter bound looser one से पहले आए, या एक later branch unreachable बन जाता है। Indentation यहां block structure है, एक style choice नहीं, इसलिए tabs और spaces को mix करना एक TabError है बजाय meaning में एक silent shift के।

python
score = 87

if score >= 90:
    print("A grade")
elif score >= 80:
    print("B grade")
elif score >= 70:
    print("C grade")
else:
    print("Below C")

नियम:

  • if required है और हमेशा पहली आती है
  • elif (short for "else if") optional है और आपको जितनी चाहे उतनी चाहिए
  • else optional है, सब कुछ handle करता है जो match नहीं हुआ, और last आता है
  • Python indentation (4 spaces) use करता है यह mark करने के लिए कि क्या हर block के अंदर belongs है; कोई braces नहीं हैं

Indentation optional या cosmetic नहीं है। Python इसे structure define करने के लिए use करता है। Inconsistent indentation एक syntax error है।

Junoif / elif / elseif अपना block चलाता है जब condition true है, elif अधिक cases check करता है, else बाकी catch करता है। केवल पहली match चलती है। चीज़ जिसने मुझे जल्दी में confused किया: indentation है जो Python को बताता है कि हर block कहां start और end होता है, इसलिए इसे consistent रखें।
Junoif / elif / else Conditions को ऊपर से नीचे check किया जाता है और केवल पहली match चलती है, इसलिए order मायने रखता है: narrower ranges को wider ones से पहले डालें। Indentation (4 spaces) block को mark करता है, और इसे mix करना एक `SyntaxError` है, एक quiet bug नहीं।
Junoif / elif / else Conditions lazily evaluate करते हैं, ऊपर से नीचे, इसलिए सबसे सस्ता या सबसे likely test पहले डालें और overlapping bounds को tight-before-loose order करें या एक branch dead जाता है। Indentation structure है, style नहीं, और tabs-vs-spaces एक `TabError` है बजाय एक silent shift के।

One-line conditions

simple yes/no assignments के लिए, Python के पास एक compact one-line form है जिसे ternary expression कहते हैं: value_if_true if condition else value_if_false। इसे केवल तभी use करें जब logic छोटा हो और एक sentence की तरह पढ़ता हो।

conditional expression (ternary operator) एक condition के आधार पर दो values में से एक को evaluate करता है। यह एक statement नहीं एक expression है, इसलिए यह कहीं भी एक value expected है: एक f-string के अंदर, एक function argument के रूप में, एक assignment में। सरल yes/no cases के लिए इसे use करें; कुछ भी involving elif के लिए, full version लिखें।

conditional expression x if condition else y condition को evaluate करता है और बिना दूसरे को run किए एक side return करता है, इसलिए यह safe है use करने के लिए जहां एक branch अन्यथा error करता। क्योंकि यह एक expression है, यह कहीं भी एक value जाता है में slots करता है: एक f-string, एक function argument, एक default। discipline है जानना कब stop करें। यह एक elif hold नहीं कर सकता और इसे chain करना (a if p else b if q else c) उससे भी worse पढ़ता है जिसे यह replace करता है, इसलिए एक बार जब आपके पास एक से अधिक decision हो, full if/elif/else के लिए reach करें। जो reader बाद में यह maintain करता है वह आपको thank करेगा।

python
label = "pass" if score >= 50 else "fail"

यह एक ternary expression है; यह एक sentence की तरह पढ़ता है। इसे use करें जब logic छोटा हो। कुछ भी involving elif के लिए, full version लिखें।

JunoOne-line conditionsvalue_if_true if condition else value_if_false एक ही line पर दो values में से एक pick करता है। यह तidy little choices के लिए lovely है जैसे "pass" if score >= 50 else "fail"। जिस moment logic उससे अधिक grow करता है, एक normal `if` block पर वापस जाएं, यह better पढ़ेगा।
JunoOne-line conditions ternary एक expression है, इसलिए यह कहीं भी एक value करता है में fit करता है: एक f-string, एक argument, एक assignment। सरल two-way choices के लिए इसे use करें। कुछ भी एक `elif` के साथ एक full block में belongs है।
JunoOne-line conditionsx if cond else y केवल side को चलाता है जिसे यह pick करता है, इसलिए यह safe है जहां एक branch raise करता, और यह किसी भी expression slot में drops करता है। उन्हें chain न करें: stacked ternaries उससे worse पढ़ते हैं जिसे वे replace करते हैं, इसलिए एक decision के past, इसे out लिखें।

while loops

एक while लूप अपने block को repeat करता है जब तक इसकी condition True है। इसे use करें जब आप advance में नहीं जानते कि लूप कितनी बार चलना चाहिए, उदाहरण के लिए valid input के लिए wait करना या जब तक एक job success न हो तब तक retry करना।

while अपनी condition को हर iteration से पहले evaluate करता है और block को केवल तभी चलाता है जब condition truthy हो। इसे use करें loops के लिए जहां exit condition पर depend करता है कुछ पर जो loop के अंदर change होता है। जब iterations की संख्या known हो या आप एक collection iterate कर रहे हो, for usually cleaner है।

while हर pass से पहले अपनी condition को re-test करता है, और body वह है जो उस condition को change करता है, इसलिए failure mode structural है: forget करें exit की ओर move करने के लिए (counter को decrement करें, queue को consume करें) और आपको एक loop मिलता है जो कभी नहीं ends और एक process जो hangs करता है। idiomatic shape जब exit को body के middle या end में decide होना होता है वह है while True एक interior break के साथ, जो condition को जहां यह actually happens वहां रखता है बजाय इसे header में force करने के। कुछ भी एक collection walk करने या एक known number of times चलाने के लिए, एक for लूप cleaner है और off-by-one में एक chance को remove करता है।

python
lives = 3

while lives > 0:
    print(f"Lives remaining: {lives}")
    lives -= 1

print("Game over")

while best है जब आप advance में नहीं जानते कि लूप कितनी बार चलेगा। जब आप जानते हो, या जब आप एक collection iterate कर रहे हो, for cleaner है।

Junowhile loopswhile अपने block को तब तक चलाते रहता है जब तक condition true रहता है। इसे reach करें जब आप नहीं जानते कि आपको कितने rounds की जरूरत है, जैसे valid input के लिए wait करना। सुनिश्चित करें कि loop के अंदर कुछ exit की ओर move करता है, या यह forever चलेगा, एक गलती जो मैंने एक से अधिक बार की है।
Junowhile loopswhile हर pass से पहले अपनी condition को check करता है और body वह है जो इसे change करता है। इसे use करें जब exit कुछ पर depend करता है जो loop के अंदर happen होता है। अगर आप count कर रहे हो या एक collection walk कर रहे हो, `for` cleaner pick है।
Junowhile loops Body को exit की ओर move करना होता है या आपको एक hang मिलता है, इसलिए वह पहली चीज़ है check करने के लिए। `while True` एक interior `break` के साथ clean shape है जब exit body के mid-land करता है। एक known count या एक collection के लिए, `for` prefer करें और off-by-one risk को skip करें।

break और continue

break लूप को immediately exit करता है, कितने भी iterations remain हों। continue current iteration के rest को skip करता है और condition check में वापस jump करता है। दोनों केवल innermost loop को affect करते हैं जो वे अंदर हैं।

break nearest enclosing लूप को terminate करता है, control को पहली statement में transfer करता है इसके बाद। continue loop body के remainder को skip करता है और restart करता है condition check से (या for लूप में next iteration)। दोनों केवल nearest enclosing लूप को affect करते हैं।

break लूप को at once leave करता है और इसके else clause को skip करता है अगर इसके पास एक है; continue straight back को loop header में jump करता है next pass के लिए। दोनों nearest enclosing लूप को bind करते हैं, और Python के पास कोई labelled break नहीं है, इसलिए वे एक outer लूप को एक inner से reach नहीं कर सकते। जब आपको एक बार में कई levels escape करने की जरूरत है, clean move nested लूप को एक function में lift करना और return करना है, जो better पढ़ता है एक flag variable को दोनों में thread करने से। एक flag काम करता है, लेकिन हर extra if found: जिसे आप add करते हो missing label को dodge करने के लिए वह एक जगह है जहां एक future edit इसे गलत कर सकता है।

break लूप को immediately exit करता है:

python
target = 5
num = 0

while True:
    num += 1
    if num == target:
        print(f"Found {target}")
        break   # stop the loop

while True: एक break के साथ एक valid और common pattern है जब exit condition complex है या loop body के end में happen करने की जरूरत है।

continue current iteration के rest को skip करता है और condition check में वापस जाता है:

python
num = 0

while num < 10:
    num += 1
    if num % 2 == 0:
        continue    # skip even numbers
    print(num)      # only odd numbers print: 1, 3, 5, 7, 9
Junobreak और continuebreak लूप से right away jump करता है, continue इस round के rest को skip करता है और condition check में वापस जाता है। दोनों केवल loop को touch करते हैं जो वे directly अंदर हैं। `while True:` एक `break` के साथ odd read करता है at first, लेकिन यह एक normal तरीका है जब तक कुछ happen न हो loop करने का।
Junobreak और continuebreak nearest लूप को leave करता है, continue इसे condition से restart करता है। दोनों एक outer लूप को reach नहीं करते। nested लूप से bail out करने के लिए, एक flag set करें या inner लूप को एक function में pull करें और `return` करें।
Junobreak और continue दोनों nearest लूप को bind करते हैं, और कोई labelled `break` नहीं है, इसलिए कई levels को escape करने का मतलब एक flag है या, cleaner, `return` के साथ एक function। `break` loop के `else` को भी skip करता है, जो exactly वह है जो search pattern पर rely करता है।

for loops

एक for लूप एक sequence को एक बार में एक item चलता है: एक list, एक string, संख्याओं की एक range। variable जिसे आप for के बाद name देते हैं, वह हर बार में एक item receive करता है। आप एक counter manage नहीं करते या length को खुद check नहीं करते।

for चीज़ को आप देते हैं से एक बार में एक item के लिए ask करता है और items run out होने पर रुकता है, बजाय index positions के through count करने के। वही कारण है कि यह lists से कहीं अधिक पर काम करता है: strings, dictionaries, ranges, और file objects सभी same तरीके से लूप करते हैं, आपकी ओर से कोई length check या counter के बिना। for को reach करें while के ऊपर जब भी आप एक collection walk कर रहे हों।

for indexes count नहीं करता, यह चीज़ को आप देते हैं से एक iterator के लिए ask करता है (एक object जो एक बार में एक item hand out करता है और याद रखता है कहां यह stop हुआ) और items को तब तक pull करता है जब तक वे run out न हों। practical payoff यह है कि for lists से कहीं अधिक पर काम करता है: strings, dictionaries, ranges, file objects, और lazy sources जैसे generators (sequences computed on demand, कभी सभी memory में held नहीं) सभी same तरीके से लूप करते हैं। वह last group है जहां एक gotcha live करता है: एक lazy iterator single-use है, इसलिए एक बार for लूप एक generator या एक file को drain करता है, इसे फिर से loop करना आपको कुछ नहीं देता। अगर आपको items दो बार चाहिए, उन्हें पहले एक list में materialise करें या source को फिर से open करें।

python
players = ["राज", "प्रिया", "अमित"]

for player in players:
    print(f"नमस्ते, {player}!")

for लूप strings पर भी काम करते हैं (character-by-character iterate करते हुए) और किसी भी दूसरे sequence type पर।

Junofor loopsfor item in sequence हर item को एक-एक करके चलता है, और आप कभी एक counter या एक length को खुद touch नहीं करते। यह lists, strings, ranges, बहुत सारी चीजों पर काम करता है। दूसरी भाषाओं से आते हुए, index को manage न करना मुझे at first अजीब लगा, फिर यह एक gift की तरह लगा।
Junofor loopsfor एक बार में एक item pull करता है जब तक वे run out न हों, इसलिए यह indexed sequences तक tied नहीं है। Lists, strings, dicts, ranges, files: सभी के लिए same loop। कोई index bookkeeping नहीं, कोई length checks नहीं।
Junofor loopsfor किसी भी iterator को drive करता है, इसलिए lists, files, और generators सभी alike लूप करते हैं। catch lazy ones में है: एक generator या file iterator single-use है, एक pass के बाद drained। items को दो बार चाहिए? पहले उन्हें एक list में pull करें या source को reopen करें।

range()

range() आपके लिए numbers की एक sequence generate करता है loop करने के लिए। range(5) आपको 0, 1, 2, 3, 4 देता है। आप start, end, और step size को control कर सकते हैं। इसे use करें जब आप एक लूप को एक specific number of times चलाना चाहते हैं।

range(start, stop, step) start से stop तक (लेकिन including नहीं) integers produce करता है, step से stepping करते हुए। यह एक lazy sequence है: यह एक list create नहीं करता, यह on demand numbers generate करता है। यह range(10_000_000) को memory-efficient बनाता है। सभी तीनों forms negative arguments accept करते हैं reverse counting के लिए।

एक range कभी numbers की list build नहीं करता, यह केवल start, stop, और step को store करता है और हर value को जाते जाते work करता है। वह range(10_000_000) को same memory cost बनाता है जैसे range(10), इसलिए जब आप केवल iterate करना चाहते हैं, range को directly loop करें बजाय इसे list() में wrap करने के और दस million stored integers के लिए pay करने के। यह अभी भी एक sequence की तरह behave करता है जहां यह count करता है: आप इसे index कर सकते हैं, slice कर सकते हैं, len() ask कर सकते हैं, और in के साथ membership को test कर सकते हैं, सभी cheaply। list(range(n)) को call करना केवल worth है जब आपको वास्तव में एक real, reusable list की जरूरत है hold करने के लिए।

python
for i in range(5):
    print(i)    # 0, 1, 2, 3, 4

range() के तीन forms हैं:

CallWhat it produces
range(5)0, 1, 2, 3, 4
range(2, 6)2, 3, 4, 5
range(0, 10, 2)0, 2, 4, 6, 8 (step of 2)
range(5, 0, -1)5, 4, 3, 2, 1 (counting down)

range() एक list create नहीं करता। यह एक बार में numbers produce करता है, जो बहुत बड़े ranges के लिए भी efficient है।

Junorange()range(5) आपको `0, 1, 2, 3, 4` देता है, और आप एक start, stop, और step set कर सकते हैं। इसे reach करें जब आप एक लूप को एक set number of times चलाना चाहते हैं। यह एक list build नहीं करता, यह आपको एक बार में एक number hand करता है।
Junorange()range(start, stop, step) `start` से `stop` तक counting करता है (including नहीं)। यह एक lazy sequence है, इसलिए यह एक list build करने के बजाय on demand numbers बनाता है, जो कि `range(10_000_000)` लगभग nothing को cost करता है। Negative steps count down करते हैं।
Junorange() एक `range` केवल start, stop, और step को store करता है, इसलिए यह flat memory है कितना भी बड़ा हो। इसे directly loop करें बजाय `list(range(n))` के जब तक आपको वास्तव में एक reusable list की जरूरत न हो। यह अभी भी cheaply को indexes, slices, और `in` और `len()` को support करता है।

enumerate()

enumerate() आपको loop करते हुए index और value दोनों देता है, इसलिए आपको एक counter separately track नहीं करना होता। i, player part automatically हर iteration पर एक pair of values receive करता है।

enumerate(iterable, start=0) किसी भी iterator को wrap करता है और (index, value) tuples yield करता है। start parameter counter को offset करता है लेकिन underlying index को change नहीं करता। एक counter variable manage करने के ऊपर enumerate() को prefer करें; यह cleaner है और कम error-prone है।

enumerate किसी भी iterable को wrap करता है और (count, value) pairs hand back करता है, जिसे for header unpacking के माध्यम से दो names में split करता है (Python एक tuple के हर part को एक ही step में अपना नाम assign करता है)। यह lazy है और counter के परे कुछ नहीं add करता है, इसलिए यह bare loop के समान cost करता है। reason को हमेशा reach करने के लिए एक hand-managed index = 0; index += 1 के ऊपर reliability है: manual version उस bug को invite करता है जहां आप increment को forget करते हो या इसे wrong जगह में bump करते हो, और enumerate उस पूरे mistake class को remove करता है। start=1 pass करें जब आप output को number कर रहे हों लोगों के लिए, जो zero नहीं एक से count करते हैं।

python
players = ["राज", "प्रिया", "अमित"]

for i, player in enumerate(players):
    print(f"{i + 1}. {player}")
# 1. राज
# 2. प्रिया
# 3. अमित

i, player syntax को unpacking कहते हैं। Python (index, value) pair को दो names में automatically split करता है।

By default enumerate() 0 से start करता है। एक start value pass करें वह change करने के लिए:

python
for i, player in enumerate(players, start=1):
    print(f"{i}. {player}")    # starts at 1
Junoenumerate()enumerate() आपको position और value together hand करता है, इसलिए कोई separate counter नहीं जिसे sync में रखना होता है। `i, player` part दोनों को at once catch करता है। `start=1` pass करें जब आप एक list को number कर रहे हों किसी को read करने के लिए।
Junoenumerate() `enumerate(iterable, start=0)` `(index, value)` pairs yield करता है जो `for` header में right unpack करते हैं। एक counter variable के लिए इसे prefer करें, यह cleaner है और आप increment को forget नहीं कर सकते। `start` केवल displayed number को shift करता है, real index को नहीं।
Junoenumerate() Lazy, counter के परे free, और यह पूरे "forgot to increment" bug को delete करता है जो एक manual index invite करता है, इसलिए default से इसे reach करें। हर item एक tuple है, जो कि है क्यों `for i, v` unpacking काम करता है। `start=1` human-facing numbering के लिए।

नीडेड loops

आप एक loop को दूसरे loop के अंदर रख सकते हैं। inner loop पूरी तरह से outer loop के हर single iteration के लिए चलता है। यही है कि आप grids, combinations, या दो levels की structure के साथ कोई भी data को process कैसे करते हैं।

Nested loops के पास outer length m के लिए O(m × n) iteration count होता है और inner length n। एक nested लूप के अंदर break और continue केवल innermost लूप को affect करते हैं। कई levels से breaking out के लिए, एक flag variable का use करें या एक function में restructure करें।

Nested loops multiply करते हैं: एक outer लूप length m के around एक inner length n का m times n times body को चलाता है, इसलिए cost fast climb करता है और एक pair of loops बड़े inputs के over slow script के पीछे usual culprit है। एक third level reach करने से पहले, ask करें क्या data structure real fix है (एक dictionary lookup एक inner search लूप को collapse कर सकता है)। जब आपको केवल दो sequences के हर combination की जरूरत है (एक Cartesian product, दूसरे के साथ एक का हर pairing), standard library से itertools.product nesting से better reads करता है। और याद रखें break केवल inner लूप को exit करता है: दोनों को leave करने के लिए, उन्हें एक function में lift करें और return करें।

python
rows = [1, 2, 3]
cols = ["A", "B"]

for row in rows:
    for col in cols:
        print(f"{col}{row}", end=" ")
    print()   # newline after each row
# A1 B1
# A2 B2
# A3 B3

एक nested लूप के अंदर break और continue केवल innermost लूप को affect करते हैं।

JunoNested loops एक loop एक loop के अंदर outer के हर single round के लिए पूरे inner लूप को चलाता है। वही है कि आप grids और combinations को कैसे handle करते हैं। `break` और `continue` केवल loop पर act करते हैं जो वे अंदर sit करते हैं, inner one यहां।
JunoNested loops Inner loop outer step में full चलता है, इसलिए count m times n है, बड़े inputs पर इसे watch करें। `break` और `continue` केवल innermost लूप को reach करते हैं। दोनों से escape करने के लिए, एक flag use करें या उन्हें एक function में pull करें और `return` करें।
JunoNested loops Costs multiply करते हैं, इसलिए big inputs के over nested loops usual slow spot हैं; sometimes एक dict lookup inner one को completely replace करता है। हर pairing के लिए, `itertools.product` nesting को beat करता है। `break` केवल inner लूप को hit करता है, इसलिए `return` के साथ एक function दोनों से बाहर का clean तरीका है।

लूप-else

Python लूप के पास एक else clause हो सकता है जो केवल तभी चलता है अगर लूप break को hit किए बिना finish हुआ। यह commonly use नहीं है, लेकिन यह "एक list search करें, और अगर कुछ नहीं मिला, यह करो" लिखने का cleanest तरीका है।

एक for या while लूप पर else execute करता है अगर लूप normally complete होता है (iterable को exhaust करता है या condition false हो जाता है) बिना एक break को hit किए। यह idiomatic pattern है "search और report if not found" के लिए एक separate found-flag variable की जरूरत के बिना।

लूप else केवल तभी चलता है जब लूप break के बिना finish होता है, जो अधिकांश लोगों को read करने के opposite है (यह नहीं है "else, लूप did not चलाएं")। वह naming exactly है क्यों यह readers को confuse करता है, इसलिए production में rule एक चीज़ के लिए इसे use करना है और एक ही चीज़: search-and-not-found pattern, जहां break एक hit को mark करता है और else miss को report करता है। यह found = False flag को replace करता है जिसे आप अन्यथा लूप के through carry करेंगे। कहीं और, cleverness cost करता है बहुत confused reviewers में कि यह save करता है, इसलिए else पर एक comment line के worth है।

python
target = "राज"
names = ["प्रिया", "अमित", "सुनीता"]

for name in names:
    if name == target:
        print(f"Found {target}")
        break
else:
    print(f"{target} not in list")   # runs because break never fired

अगर break चलता है, else को skip किया जाता है। अगर लूप sequence को exhaust करता है, else चलता है। यह एक niche pattern है लेकिन एक flag variable से cleaner है।

Junoलूप-else एक लूप के पास एक `else` हो सकता है जो केवल तभी चलता है जब लूप एक `break` के बिना end होता है। यह often use नहीं है, लेकिन यह "इस list को search करें, और अगर कुछ नहीं matched, यह करो" कहने का neatest तरीका है। नाम एक छोटा सा misleading है, इसलिए एक short comment helps करता है।
Junoलूप-else लूप `else` fires करता है जब लूप normally finish होता है, कोई `break` नहीं। यह tidy "search और report if not found" pattern है, कोई found-flag नहीं चाहिए। इसे उस एक use तक रखें, क्योंकि नाम लोगों को throw off करता है।
Junoलूप-else यह लूप के `break` के बिना end होने पर चलता है, जो reverse है कि word कैसे reads करता है। इसे search-and-not-found case तक रखें, जहां यह एक `found = False` flag को replace करता है, और इसे comment करें। कहीं और यह more cost करता है confused reviewers में कि यह save करता है।

सॉर्टिंग

sorted() एक नई sorted list return करता है और original को unchanged रखता है। .sort() list को in place sort करता है और None return करता है। key= argument आपको raw value के अलावा कुछ और से sort करने देता है। उदाहरण के लिए, names को case-insensitively sort करना या player tuples को उनके score से sort करना।

sorted() safe default है: यह कभी original को modify नहीं करता। .sort() in place modify करता है और None return करता है। दोनों descending order के लिए reverse=True accept करते हैं। key= argument एक function लेता है comparison से पहले हर element पर apply किया जाता है। यह sorting criterion को data से separate करता है।

Python की sort stable है, meaning items जो equal compare करते हैं अपना original order रखते हैं, जो आपको stages में sort करने देता है: पहले name से sort करें, फिर score से, और same score वाले players name order में रहते हैं। key= function हर element पर एक बार run होता है, एक बार per comparison नहीं, इसलिए एक महंगा key n times computed होता है, n log n times नहीं, और आपको शायद ही कभी इसे खुद cache करने की जरूरत होती है। .sort() purpose पर None return करता है, आपको scores = scores.sort() लिखने से रोकने के लिए और silently अपनी list को wipe करने के लिए, इसलिए in-place call को अपनी own line पर stand करना होता है। default से sorted() को reach करें और .sort() को तब तक रखें जब आप actually original को mutate करना चाहते हैं।

python
scores = [87, 42, 96, 55, 71]

ranked = sorted(scores)           # [42, 55, 71, 87, 96] (new list)
scores.sort()                     # sorts the original list, returns None
scores.sort(reverse=True)         # [96, 87, 71, 55, 42]

दोनों एक key= argument accept करते हैं: एक function comparison से पहले हर item पर apply किया जाता है:

python
names = ["सुनीता", "राज", "प्रिया"]
sorted(names, key=str.lower)       # case-insensitive sort

players = [("राज", 87), ("प्रिया", 96), ("अमित", 55)]
sorted(players, key=lambda p: p[1])   # sort by score

lambda p: p[1] एक one-line function है: यह एक player tuple लेता है और score return करता है। Lambdas को Lambdas और comprehensions अध्याय में full treatment मिलता है।

सरल cases के लिए, sorted() का use करें। Lists के लिए जहां आप in place modify करना चाहते हैं, .sort() का use करें।

Junoसॉर्टिंग `sorted()` एक नई sorted list hand back करता है और original को alone छोड़ता है, `.sort()` list को खुद rearrange करता है और `None` return करता है। raw value के अलावा कुछ और से sort करने के लिए `key=` pass करें, जैसे names case-insensitively। doubt में, `sorted()` के लिए reach करें, यह safe one है।
Junoसॉर्टिंग `sorted()` कभी original को touch नहीं करता, `.sort()` in place mutate करता है और `None` return करता है। दोनों `reverse=True` लेते हैं और एक `key=` function comparing से पहले हर element पर apply होता है। `sorted()` को default करें; `.sort()` को केवल तब use करें जब आप list को change करना mean करते हैं।
Junoसॉर्टिंग सॉर्टिंग stable है, इसलिए stages में sort करें और ties अपना order रखते हैं। `key=` एक बार per element run करता है, per comparison नहीं, इसलिए इसे pre-cache न करें। और `.sort()` purpose पर `None` return करता है: `x = x.sort()` आपकी list को wipes करता है, इसलिए in-place call को अपनी own line पर रखें।

वास्तविक practice में

scores के through loop करें, एक total को accumulate करें, passing grades को count करें, और एक summary print करें:

python
raw_scores = [87, 42, 96, 55, 71, 63]

total = 0
passing = 0

for score in raw_scores:
    total += score
    if score >= 60:
        passing += 1

average = total / len(raw_scores)
print(f"Average: {average:.1f}")
print(f"Passing: {passing}/{len(raw_scores)}")
print(f"Top score: {sorted(raw_scores, reverse=True)[0]}")

sorted order में files की एक list को process करें, जो बहुत बड़ी हैं उन्हें skip करें, और कितने को skip किया गया report करें:

python
files = [
    {"name": "report_jan.csv", "size_mb": 12},
    {"name": "report_feb.csv", "size_mb": 850},
    {"name": "report_mar.csv", "size_mb": 7},
]

MAX_SIZE = 100
skipped = 0

for f in sorted(files, key=lambda x: x["name"]):
    if f["size_mb"] > MAX_SIZE:
        print(f"Skipping {f['name']} ({f['size_mb']} MB, too large)")
        skipped += 1
    else:
        print(f"Processing {f['name']}...")

print(f"\nDone. {skipped} file(s) skipped.")

एक request log को errors के लिए scan करें, फिर एक retry लूप का use करें जो success पर exit करता है या जब attempt limit hit हो:

python
requests = [
    {"method": "GET", "path": "/users", "status": 200},
    {"method": "POST", "path": "/users", "status": 201},
    {"method": "GET", "path": "/broken", "status": 500},
]

errors = []

for req in requests:
    if req["status"] >= 400:
        errors.append(req)

if errors:
    print(f"{len(errors)} error(s) in request log:")
    for err in errors:
        print(f"  {err['method']} {err['path']} -> {err['status']}")
else:
    print("All requests succeeded")

attempts = 0
max_retries = 3
success = False

while attempts < max_retries and not success:
    attempts += 1
    print(f"Attempt {attempts}...")
    success = attempts >= 2   # simulate success on second try

print("Connected" if success else "Failed after all retries")