एक्सेप्शन्स — टूटी हुई स्थिति को संभालना
try/except से विशिष्ट त्रुटि पकड़ना, except Exception: pass लगभग हमेशा गलत क्यों है, else और finally, स्वयं raise करना, और सही स्तर की त्रुटि चुनना।
- 1समस्या
- 2समझें
- 3उदाहरण
- 4अनुमान
- 5स्वयं करें
- 6चुनौती
वह समस्या जिसे हम हल कर रहे हैं
पिछले अध्याय के अंतिम प्रश्न में एक प्रोग्राम ने तीन पंक्तियों को सही ढंग से संसाधित किया और चौथी पर रुक गया। छोटे रूप में यह ऐसा दिखता है:
numbers = ["10", "twenty", "30"]
total = 0
for text in numbers:
total += int(text)
print(total)ValueError: invalid literal for int() with base 10: 'twenty'10 सही तरीके से जोड़ा गया था। 30 कभी नहीं जोड़ा गया। और print(total) कभी नहीं चला।
एक खराब लाइन ने पूरे काम को रोक दिया। अब तक हमारे पास केवल दो विकल्प थे — या तो डेटा का प्रत्येक हिस्सा सही हो, या प्रोग्राम रुक जाए।
numbers = ["10", "twenty", "30"]
total = 0
for text in numbers:
try:
total += int(text)
except ValueError:
print("skipping", text)
print(total)skipping twenty
40एक तीसरा विकल्प है: समस्या को होने दें, और फिर उसका उत्तर दें।
इस मिशन के अंत तक आप सीखेंगे
try/exceptके साथ एक विशिष्ट त्रुटि को पकड़ना- यह समझना कि
except Exception: passलगभग हमेशा गलत क्यों होता है as errके साथ त्रुटि को पकड़ना और उसका संदेश पढ़नाelseऔरfinallyक्या करते हैं- अपनी स्वयं की त्रुटियाँ
raiseकरना - त्रुटियों के परिवार (hierarchy) को पहचानना, और सही स्तर की त्रुटि पकड़ना
पूर्वापेक्षाएँ: फ़ाइलें पढ़ना और लिखना.
एक त्रुटि भी एक ऑब्जेक्ट है
as लिखने से त्रुटि आपके हाथों में आ जाती है:
try:
int("twenty")
except ValueError as err:
print(type(err))
print(err)<class 'ValueError'>
invalid literal for int() with base 10: 'twenty'टर्मिनल में आप जो लाल टेक्स्ट देखते रहे हैं, वह यही ऑब्जेक्ट्स हैं, और इसे प्रिंट करने पर इसका संदेश मिलता है।
सही त्रुटि को पकड़ें
try:
int("twenty")
except TypeError:
print("caught")ValueError: invalid literal for int() with base 10: 'twenty'except केवल उसी प्रकार को पकड़ता है जिसका वह नाम लेता है। इसने TypeError नाम लिया, और जो हुआ वह ValueError था — इसलिए यह नहीं रुका।
इसीलिए आपको यह कभी नहीं लिखना चाहिए:
numbers = ["10", "twenty", "30"]
total = 0
for text in numbers:
try:
total += int(text)
except Exception:
pass
print(total)40उत्तर सही है लेकिन कोड बुरा है। except Exception: pass सब कुछ निगल जाता है — वे विफलताएं जिनके बारे में आपने सोचा था और वे भी जिनके बारे में आपने नहीं सोचा था। जब कल कोई नाम गलत टाइप होगा, तो यह प्रोग्राम चुपचाप गलत उत्तर दे देगा।
नियम: ठीक वही त्रुटि पकड़ें जिसकी आपने योजना बनाई है।
एक से अधिक प्रकार
def get(data, key):
try:
return data[key]
except KeyError:
return "no such key"
except IndexError:
return "no such position"
print(get({"pen": 15}, "pen"))
print(get({"pen": 15}, "bag"))
print(get([1, 2, 3], 9))15
no such key
no such positionजब प्रतिक्रिया समान हो तो उन्हें एक साथ लिखा जा सकता है:
for value in ["10", None, "x"]:
try:
print(int(value))
except (ValueError, TypeError) as err:
print(type(err).__name__, "-", err)10
TypeError - int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
ValueError - invalid literal for int() with base 10: 'x'त्रुटियाँ परिवारों में आती हैं
print(issubclass(FileNotFoundError, OSError))
print(issubclass(ValueError, Exception))
print(issubclass(KeyError, LookupError))
print(issubclass(IndexError, LookupError))True
True
True
Trueत्रुटियाँ एक वृक्ष (tree) के रूप में व्यवस्थित होती हैं, और पैरेंट को पकड़ने से उसके बच्चे भी पकड़ में आ जाते हैं:
try:
raise FileNotFoundError("gone")
except OSError as err:
print("caught as OSError:", err)caught as OSError: goneनियम: जितनी छोटी और विशिष्ट त्रुटि हो सके, उसे ही पकड़ें।
else और finally
def read(text):
try:
value = int(text)
except ValueError:
print("bad:", text)
return None
else:
print("good:", value)
return value
finally:
print("done with", text)
print(read("10"))
print(read("ten"))good: 10
done with 10
10
bad: ten
done with ten
Noneelse तब चलता है जब try ब्लॉक में कुछ भी नहीं टूटा।
finally हमेशा चलता है, चाहे कुछ भी हुआ हो। return के बाद भी:
def risky():
try:
return "from try"
finally:
print("finally still runs")
print(risky())finally still runs
from tryअपनी त्रुटियाँ स्वयं उठाना (raise)
त्रुटि फेंकना (raise करना) उतना ही महत्वपूर्ण है जितना पकड़ना।
def line_total(price, quantity):
if quantity < 0:
raise ValueError(f"quantity cannot be negative: {quantity}")
return price * quantity
print(line_total(15.0, 3))
print(line_total(15.0, -1))45.0
ValueError: quantity cannot be negative: -1raise का विकल्प क्या था? None या 0 लौटाना — और तब गलती आगे बढ़ती रहती। एक त्रुटि गलती को वहीं रोक देती है जहाँ उसका जन्म हुआ था।
संदेश लिखते समय, उसमें गलत मान शामिल करें।
त्रुटि को पकड़ा भी जा सकता है और बेहतर संदेश के साथ फिर से उठाया जा सकता है:
def parse(text):
try:
return int(text)
except ValueError:
raise ValueError(f"not a number: {text!r}")
print(parse("10"))
print(parse("ten"))10
ValueError: not a number: 'ten'एक संपूर्ण उदाहरण
orders.txt:
pen,15.0,3
bag,eight,1
ink,120.0,2
clip,5.0main.py:
"""एक ऑर्डर फ़ाइल पढ़ें, और किसी पंक्ति के गलत होने पर भी चलते रहें।"""
from pathlib import Path
TAX_RATE = 0.15
def parse_line(raw, number):
"""एक ऑर्डर लाइन लौटाता है, या यह बताते हुए ValueError उठाता है कि कौन सी लाइन गलत थी।"""
parts = raw.split(",")
if len(parts) != 3:
raise ValueError(f"line {number}: expected 3 fields, got {len(parts)}")
name, price, quantity = parts
try:
return name, float(price), int(quantity)
except ValueError as err:
raise ValueError(f"line {number}: {err}")
def read_order(path):
"""सही लाइनों और शिकायतों को लौटाता है, खराब डेटा के लिए कभी क्रैश नहीं होता।"""
try:
text = path.read_text(encoding="utf-8")
except FileNotFoundError:
return [], [f"no such file: {path}"]
lines = []
problems = []
for number, raw in enumerate(text.splitlines(), start=1):
if not raw.strip():
continue
try:
lines.append(parse_line(raw, number))
except ValueError as err:
problems.append(str(err))
return lines, problems
def main():
lines, problems = read_order(Path("orders.txt"))
total = 0.0
for name, price, quantity in lines:
amount = round(price * quantity * (1 + TAX_RATE), 2)
total += amount
print(f"{name:<6} {amount:>9.2f}")
print(f"{'total':<6} {total:>9.2f}")
print()
print(f"{len(lines)} lines used, {len(problems)} skipped")
for problem in problems:
print(" -", problem)
if __name__ == "__main__":
main()pen 51.75
ink 276.00
total 327.75
2 lines used, 2 skipped
- line 2: could not convert string to float: 'eight'
- line 5: expected 3 fields, got 2जब यह टूटता है
except होने के बावजूद त्रुटि नहीं पकड़ी जा रही है प्रकार मेल नहीं खाता। संदेश का पहला शब्द त्रुटि का नाम है।
except Exception: pass से उत्तर गलत आ रहे हैं इसे कोड से निकालें — यह वास्तविक बग्स को छुपा रहा है।
raise किया लेकिन कोई संदेश नहीं दिखा raise ValueError("...") के बजाय raise ValueError लिखा गया था। कोष्ठक और संदेश जोड़ें।
चरण 4 / 6 — अनुमान
अपनी समझ की जाँच करें
There is an except. What happens to the program?
try:
int("twenty")
except TypeError:
print("caught")- AThe program stops with a `ValueError` — the `except` may as well not be there
- B`caught` prints
- CNothing prints and the program ends quietly
- DIt stops with a `TypeError`
The whole loop is inside the try. What is printed?
values = ["10", "x", "30"]
total = 0
try:
for text in values:
total += int(text)
except ValueError:
print("gave up")
print(total)- Agave up 10
- Bgave up 40
- Cgave up 0
- D40
Both the try and the except have a return. What is printed?
def read(text):
try:
return int(text)
except ValueError:
return 0
finally:
print("checked", text)
print(read("7"))
print(read("seven"))- Achecked 7 7 checked seven 0
- B7 checked 7 0 checked seven
- Cchecked 7 7 0
- D7 0
उत्तर देने के लिए अकाउंट आवश्यक है
अपने उत्तर जाँचने के लिए साइन इन करें
प्रश्न ऊपर दिए गए हैं, और मन में उत्तर सोचना ही मुख्य कार्य है। सही उत्तर, व्याख्या और तीन-स्तरीय संकेत देखने के लिए साइन इन करें।
आपकी बारी
पिछले अध्याय के summary.py पर वापस जाएं। अब इसे ऐसा बनाएं कि यह कभी क्रैश न हो, और अंत में यह बताए कि कौन सी पंक्तियाँ छोड़ी गईं और क्यों। एक parse_line(raw, number) लिखें जो किसी खराब पंक्ति के लिए उसमें पंक्ति संख्या के साथ ValueError उठाए।
Step 6 of 6
चुनौती — the chapter quiz
सरल से कठिन — दस प्रश्न, अंतिम वाले जानबूझकर चुनौतीपूर्ण बनाए गए हैं।
Sign in to take the quiz