पायथन में अपवाद प्रबंधन (Exception Handling)
अपवाद उठाना: raise और assert
पायथन स्वयं भी अपवाद उठाता है, और प्रोग्राम जानबूझकर भी उठा सकता है। raise कथन का रूप है raise ExceptionName(वैकल्पिक संदेश) — उदाहरण के लिए raise ValueError("marks cannot be negative")। raise के चलते ही वर्तमान खंड का शेष भाग छोड़ दिया जाता है और पायथन किसी हैंडलर की खोज करता है। assert कथन उस शर्त की जाँच करता है जिसके सत्य होने की प्रोग्रामर अपेक्षा करता है: assert expression, message। व्यंजक True हो तो कुछ नहीं होता; False हो तो पायथन संदेश सहित AssertionError उठाता है। assert इनपुट या किसी मान्यता की त्वरित जाँच है, जैसे वर्गमूल लेने से पहले संख्या का ऋणेतर होना।
उदाहरण के लिए, यह अंश पहले 13 और फिर 4 छापता है — raise के बाद की पंक्ति कभी नहीं चलती:try: print("1", end="") raise IndexError print("2", end="")except IndexError: print("3", end="")print("4")
अपवादों का प्रबंधन: try और except
त्रुटि होने पर पायथन एक अपवाद-ऑब्जेक्ट बनाकर उसे रनटाइम सिस्टम को सौंपता है — इसे अपवाद को फेंकना (throwing) कहते हैं। रनटाइम सिस्टम फिर उन कॉल्स में पीछे की ओर खोजता है जिनसे त्रुटि तक पहुँचा गया, ताकि उससे निपटने वाला कोड, अपवाद हैंडलर, मिल सके; उसका मिल जाना अपवाद को पकड़ना (catching) कहलाता है। कहीं भी हैंडलर न मिले तो प्रोग्राम रुक जाता है। जिस कोड के विफल होने की संभावना हो उसे try खंड में रखा जाता है, और हैंडलर को except खंड में, जो उस अपवाद का नाम लेता है जिसे वह संभालता है। try खंड बिना त्रुटि चल जाए तो हर except खंड छोड़ दिया जाता है।
- एक try के बाद कई except खंड हो सकते हैं, प्रत्येक अपवाद के लिए एक; पायथन पहला मेल खाने वाला खंड चलाता है और शेष छोड़ देता है।
- बिना अपवाद-नाम वाला except हर अपवाद पकड़ता है। इसे अंतिम except खंड होना चाहिए — पहले रखना स्वयं एक SyntaxError है ("default 'except:' must be last")।
- बिना मेल वाला अपवाद — जिसका नाम किसी except खंड में न हो — यहाँ नहीं संभलता; वह बाहर कॉलर तक जाता है, और कोई न पकड़े तो प्रोग्राम समाप्त हो जाता है।
एक हल किया गया अनुरेखण। प्रत्येक मद बारी-बारी से आज़माई जाती है; "x" पूर्णांक नहीं बन सकता और "0" से भाग विफल होता है, अतः योग 3 + 100 + 2 + 1000 है और प्रोग्राम 1105 छापता है:total = 0for item in ["4", "x", "6", "0"]: try: total += 12 // int(item) except ValueError: total += 100 except ZeroDivisionError: total += 1000print(total)
else और finally खंड
try कथन में दो और खंड हो सकते हैं। else खंड केवल तब चलता है जब try खंड में कोई अपवाद न उठा हो; यह उस कोड का स्थान है जो जोखिम वाला भाग सफल होने के बाद चलना चाहिए। finally खंड सदैव चलता है — try खंड सफल रहा हो, अपवाद पकड़ा गया हो, या पकड़ा ही न गया हो — इसलिए सफ़ाई का काम, जैसे फ़ाइल बंद करना, यहीं होता है। अपवाद न संभला हो तो भी finally पहले चलता है और फिर अपवाद आगे भेजा जाता है। पृष्ठ पर क्रम निश्चित है: try, फिर except खंड, फिर else, फिर finally।
| try में क्या होता है | except | else | finally |
|---|---|---|---|
| कोई अपवाद नहीं | छोड़ा जाता है | चलता है | चलता है |
| अपवाद किसी except से मेल खाता है | मेल वाला चलता है | छोड़ा जाता है | चलता है |
| अपवाद किसी से मेल नहीं खाता | कोई नहीं चलता | छोड़ा जाता है | चलता है, फिर अपवाद आगे जाता है |
done -1 है:def f(a, b): try: return a / b except ZeroDivisionError: return -1 finally: print("done", end=" ")print(f(6, 0))मुख्य बिंदु
- वाक्य-रचना त्रुटियाँ कोड पार्स होते समय पकड़ी जाती हैं, अतः कुछ नहीं चलता; अपवाद वाक्य-रचना की दृष्टि से वैध कोड के निष्पादन के दौरान उठते हैं।
- ValueError: प्रकार सही, मान ग़लत (int("3.5")); TypeError: प्रकार ग़लत ("5" + 5); IndexError, NameError, ZeroDivisionError, EOFError अपने कारण का नाम लेते हैं।
- raise जानबूझकर अपवाद फेंकता है और खंड का शेष भाग छोड़ देता है; assert की शर्त False हो तो AssertionError उठता है।
- पायथन पहला मेल खाने वाला except चलाता है; बिना नाम का except सब कुछ पकड़ता है और उसे अंत में होना चाहिए।
- else केवल तब चलता है जब try में कुछ न उठा हो; finally हर स्थिति में चलता है, return के बाद भी, और किसी असंभले अपवाद के आगे जाने से पहले भी।
- फेंकना अपवाद-ऑब्जेक्ट बनाना है; पकड़ना रनटाइम सिस्टम का उसके लिए हैंडलर ढूँढ लेना है।
अभ्यास प्रश्न (8)
उत्तर खोलने से पहले प्रत्येक प्रश्न हल करें। हर व्याख्या सही विकल्प के साथ लुभावना गलत विकल्प भी बताती है, क्योंकि अंक वहीं जाते हैं।
निम्नलिखित कोड का आउटपुट क्या है?
try:x = int("12a")print("A", end="")except ValueError:print("B", end="")else:print("C", end="")finally:print("D", end="")उत्तर देखें
उत्तर: B — BD
int("12a") try की पहली पंक्ति पर ValueError उठाता है, अतः print("A") कभी नहीं चलता; मेल वाला except B छापता है, else छोड़ा जाता है क्योंकि try साफ़ पूरा नहीं हुआ, और finally D छापता है — BD। ABD भूल जाता है कि अपवाद उठते ही try का शेष भाग छोड़ दिया जाता है, और BCD else चलाता है, जो तभी होता है जब try में कुछ न उठे।पायथन 3 में व्यंजक int("3.5") कौन-सा अपवाद उठाता है?
उत्तर देखें
उत्तर: D — ValueError
int() स्ट्रिंग तर्क स्वीकार करता है, अतः प्रकार स्वीकार्य है; विफल होता है मान, क्योंकि "3.5" वैध पूर्णांक-लिटरल नहीं है — यह ValueError है। TypeError भ्रामक विकल्प है: वह तब उठता जब प्रकार ही अनुपयोगी होता, जैसे "5" + 5 में। पंक्ति व्याकरण की दृष्टि से वैध है, अतः यह SyntaxError नहीं है, और इसमें हर नाम परिभाषित है।किसी try कथन में else खंड कब निष्पादित होता है?
उत्तर देखें
उत्तर: A — केवल तब जब try खंड बिना कोई अपवाद उठाए पूरा हो
else सफलता की शाखा है: यह केवल तब चलता है जब try खंड बिना अपवाद पूरा हो, जिससे उस सफलता पर निर्भर कोड try खंड से बाहर रहता है। "सदैव" finally का वर्णन है, else का नहीं। अपवाद पकड़ा जाए तो else के स्थान पर except खंड चलता है, और कोई मेल न खाए तो न except चलता है न else — केवल finally, अपवाद के आगे जाने से पहले।निम्नलिखित कोड क्या छापता है?
def f(a, b):try:return a / bexcept ZeroDivisionError:return -1finally:print("done", end=" ")print(f(6, 0))उत्तर देखें
उत्तर: C — done -1
6 / 0 ZeroDivisionError उठाता है, except खंड return -1 तक पहुँचता है, और फ़ंक्शन के वास्तव में लौटने से पहले finally फिर भी चलता है, जो स्पेस सहित "done " छापता है। उसके बाद ही बाहरी print को -1 मिलता है और वह उसे छापता है, अतः done -1। केवल -1 लिखना मानता है कि return, finally को छोड़ देता है, और "-1 done" क्रम उलट देता है, मानो फ़ंक्शन पूरा होने से पहले मान छप गया हो।मान लीजिए: x = -3 के बाद assert x >= 0, "negative"। assert कथन चलने पर क्या होता है?
उत्तर देखें
उत्तर: C — यह "negative" संदेश सहित AssertionError उठाता है
assert अपनी शर्त का मूल्यांकन करता है; -3 >= 0 False है, अतः पायथन AssertionError उठाता है और कॉमा के बाद वाला संदेश जोड़ देता है। अपने-आप कुछ नहीं छपता — अपवाद न संभले तो प्रोग्राम AssertionError: negative पर समाप्त होने वाले ट्रेसबैक के साथ रुक जाता है। ValueError एक अलग अपवाद है जिसे assert कभी नहीं उठाता, और assert केवल शर्त जाँचता है; वह कभी किसी चर को नहीं बदलता।अभिकथन (A): जिस पायथन स्क्रिप्ट की अंतिम पंक्ति में वाक्य-रचना त्रुटि हो, वह कुछ भी नहीं छापती, त्रुटि से ऊपर की पंक्तियों से भी नहीं। कारण (R): वाक्य-रचना त्रुटियाँ कोड पार्स होते समय, किसी भी कथन के निष्पादन से पहले, पकड़ी जाती हैं।
उत्तर देखें
उत्तर: A — A और R दोनों सत्य हैं, और R, A की सही व्याख्या है
पायथन चलाने से पहले पूरी स्क्रिप्ट पढ़ता और पार्स करता है, अतः कहीं भी वाक्य-रचना त्रुटि हो तो प्रोग्राम शुरू ही नहीं होता; दोषपूर्ण पंक्ति से ऊपर के print कथनों तक कभी नहीं पहुँचा जाता। वही पार्सिंग चरण A का कारण है, अतः R, A की व्याख्या करता है। A को असत्य मानना वाक्य-रचना त्रुटियों को अपवादों से उलझाना है, जो पहले की पंक्तियों को चलने देते हैं क्योंकि वे केवल निष्पादन के दौरान उठते हैं।एक प्रोग्रामर एक ही try के अंतर्गत पहले बिना नाम का except: खंड और उसके बाद except ValueError: खंड लिखता है। क्या होता है?
उत्तर देखें
उत्तर: D — पायथन कोड चलाने से मना करता है: बिना नाम का except अंतिम खंड होना चाहिए
बिना नाम का except हर अपवाद पकड़ता है, अतः उसके बाद के किसी खंड तक कभी पहुँचा नहीं जा सकता; पायथन इस क्रम को कोड की ही त्रुटि मानता है और कुछ भी चलाने से पहले SyntaxError: default 'except:' must be last बताता है। "बाद के खंड तक बस पहुँचा नहीं जाता" वाला उत्तर लुभाता है, पर पायथन इसे चलते समय खोजने की प्रतीक्षा नहीं करता, और किसी अपवाद के लिए केवल एक ही except खंड चलता है।अपवाद प्रबंधन में किसी अपवाद को "पकड़ने (catching)" से क्या अभिप्राय है?
उत्तर देखें
उत्तर: B — रनटाइम सिस्टम का उसके लिए उपयुक्त हैंडलर ढूँढकर चलाना
त्रुटि होने पर अपवाद-ऑब्जेक्ट बनाकर रनटाइम सिस्टम को सौंपना फेंकना है; फिर रनटाइम सिस्टम उसे संभाल सकने वाले कोड की खोज करता है, और उस हैंडलर को ढूँढकर चलाना पकड़ना है। ऑब्जेक्ट बनाना फेंकना है, प्रक्रिया का दूसरा छोर। वाक्य-रचना त्रुटियाँ पार्सिंग के दौरान मिलती हैं और प्रोग्राम उन्हें पकड़ता ही नहीं, और पकड़ने का किसी लॉग फ़ाइल से कोई संबंध नहीं।