# Python में एक्सेप्शन: try, except, else, finally, raise और अपने एक्सेप्शन

URL: https://skillaria.top/hi/guides/python/isklyucheniya-python

Python में एक्सेप्शन वह ऑब्जेक्ट है जो एरर का संकेत देता है और सामान्य प्रवाह रोक देता है, जब तक उसे try/except ब्लॉक न पकड़ ले; else तब चलता है जब कोई एरर न हो, और finally हमेशा चलता है। एक्सेप्शन खुद उठाने के लिए raise स्टेटमेंट है, जैसे raise ValueError("राशि ऋणात्मक है"), और अपना एक्सेप्शन Exception के उत्तराधिकारी क्लास से बनता है।

Python में एक्सेप्शन एक ऐसा ऑब्जेक्ट है जो एरर का संकेत देता है और कोड का सामान्य प्रवाह रोक देता है। अगर उसे किसी ने न पकड़ा हो, तो Python traceback छापता है और प्रोग्राम बंद हो जाता है। एक्सेप्शन पकड़ने के लिए `try/except` है, और खुद उठाने के लिए `raise`। यहाँ देखते हैं कि यह कैसे काम करता है, कौन-सी एरर सबसे आम हैं, और एरर संभालने को एरर छिपाने में कैसे न बदलें।

## Python में एक्सेप्शन क्या है

जब कोई ऑपरेशन पूरा न हो सके — शून्य से भाग, मौजूद न होने वाली कुंजी खोजना, शब्द को संख्या में बदलना — Python एक एक्सेप्शन ऑब्जेक्ट बनाता है और उसे «उठाता» (raise) है। मौजूदा फ़ंक्शन का काम रुक जाता है, और एक्सेप्शन कॉल की श्रृंखला में ऊपर जाता है, जब तक कोई उपयुक्त हैंडलर न मिले। न मिले तो प्रोग्राम गिर जाता है।

```
>>> 10 / 0
Traceback (most recent call last):
  File "", line 1, in
ZeroDivisionError: division by zero
```

एक आम सवाल का जवाब: Python में शून्य से भाग देने पर `ZeroDivisionError` उठता है। यह `/`, `//` और `%`, तीनों पर लागू होता है।

## traceback कैसे पढ़ें

Traceback एक रिपोर्ट है कि प्रोग्राम एरर तक कैसे पहुँचा। उसे नीचे से ऊपर पढ़ना आसान है। आख़िरी पंक्ति सबसे अहम है: एक्सेप्शन का प्रकार और संदेश। उसके ऊपर वह कोड-पंक्ति है जहाँ गड़बड़ी हुई, और उसके ऊपर वह जगह जहाँ से उसे बुलाया गया, और इसी तरह प्रवेश-बिंदु तक।

```
Traceback (most recent call last):
  File "tracker.py", line 9, in
    total = parse_amount(row)
  File "tracker.py", line 4, in parse_amount
    return float(raw.strip())
           ~~~~~^^^^^^^^^^^^^
ValueError: could not convert string to float: 'सौ'
```

Python 3.11 से कोड की लाइन के नीचे `~~~^^^` जैसे निशान बने हैं (PEP 657): वे बताते हैं कि लाइन में कौन-सा ठीक-ठीक व्यंजन टूटा। यह तब बहुत मदद करता है, जब एक ही पंक्ति में कई कॉल एक के बाद एक हों।

### «Did you mean» के सुझाव

Python 3.10 से नाम में टाइपो होने पर एरर एक नज़दीकी विकल्प सुझाता है। Python 3.15 में ये सुझाव और समझदार हो गए हैं: दूसरी भाषाओं की आदतें भी पहचानते हैं। `list.push` लिखने पर `append` सुझाया जाएगा, और `"कॉफ़ी".toUpperCase()` पर मेथड `upper`। सुझाव भीतरी फ़ील्ड भी देखते हैं: अगर डिक्शनरी ऑब्जेक्ट के `totals` एट्रिब्यूट में है और आपने सीधे ऑब्जेक्ट पर `items()` बुलाया, तो `.totals.items` सुझाया जाएगा। `delattr()` भी नज़दीकी नाम सुझाता है।

## Python एक्सेप्शन के प्रकार

बिल्ट-इन एक्सेप्शन दर्जनों हैं, पर शुरुआत में यही सबसे ज़्यादा दिखते हैं:

| एक्सेप्शन | कब उठता है | उदाहरण |
| --- | --- | --- |

| `NameError` | नाम परिभाषित नहीं, अक्सर टाइपो | `print(totl)` |

| `TypeError` | यह ऑपरेशन इस प्रकार के लिए सही नहीं | `"5" + 3` |

| `ValueError` | प्रकार सही, मान नहीं | `int("सौ")` |

| `KeyError` | डिक्शनरी में ऐसी कुंजी नहीं | `d["missing"]` |

| `IndexError` | इंडेक्स सूची की सीमा से बाहर | `[1, 2][5]` |

| `AttributeError` | ऑब्जेक्ट में ऐसा मेथड या फ़ील्ड नहीं | `[].push(1)` |

| `ZeroDivisionError` | शून्य से भाग | `1 / 0` |

| `FileNotFoundError` | फ़ाइल नहीं मिली | `open("nope.txt")` |

अलग से `SyntaxError` (और उसका ख़ास रूप `IndentationError`) देखें: यह फ़ाइल पढ़ते समय, कोड चलने से पहले उठता है, इसलिए उसी फ़ाइल में `try` से पकड़ा नहीं जा सकता।

### एक्सेप्शन का पदानुक्रम

एक्सेप्शन क्लास हैं, और वे एक पदानुक्रम (हायरार्की) में सजे हैं। शीर्ष पर `BaseException` है। उससे `Exception` (लगभग सारी «आम» एरर) और कुछ सिस्टम-स्तर वाले उत्तराधिकारी लेते हैं: `KeyboardInterrupt`, `SystemExit`, `GeneratorExit`।

```
BaseException
 ├── KeyboardInterrupt
 ├── SystemExit
 └── Exception
      ├── ArithmeticError
      │    └── ZeroDivisionError
      ├── LookupError
      │    ├── KeyError
      │    └── IndexError
      ├── OSError
      │    └── FileNotFoundError
      ├── TypeError
      └── ValueError
```

पदानुक्रम पकड़ते समय मायने रखता है: `except LookupError` `KeyError` और `IndexError`, दोनों पकड़ेगा। और `KeyboardInterrupt` कोड की गलती नहीं है: इससे Python बताता है कि उपयोगकर्ता ने Ctrl+C दबाया। वह जानबूझकर `Exception` से नहीं आता, ताकि `except Exception` प्रोग्राम को रोकने में बाधा न बने।

## एक्सेप्शन संभालना: try/except/else/finally

जो कोड गिर सकता है, उसे `try` ब्लॉक में रखा जाता है। `except` में एरर का प्रकार लिखा जाता है और बताया जाता है कि क्या करना है। यही वह ब्लॉक है जिससे Python में एक्सेप्शन संभाले जाते हैं।

```
def parse_amount(raw):
    try:
        value = float(raw)
    except ValueError as e:
        print(f"पंक्ति छोड़ी जा रही है: {e}")
        return None
    else:
        return value          # तब चलता है, जब कोई एरर न हो
    finally:
        print("पार्सिंग पूरी हुई")   # हमेशा चलता है

print(parse_amount("250"))
```

यहाँ छपाई का क्रम है: पहले «पार्सिंग पूरी हुई», फिर `250.0`। `else` ब्लॉक में `return` मान याद रखता है, फिर Python `finally` ज़रूर चलाता है और उसके बाद ही परिणाम लौटाता है। इसलिए `finally` सफ़ाई के लिए भरोसेमंद है: फ़ाइल बंद करना, कनेक्शन छोड़ना।

अगर `finally` में अपना `return` लिखा, तो वह पहले वाले को ढक देगा और एक्सेप्शन तक निगल सकता है। Python 3.14 से ऐसे कोड पर `SyntaxWarning` आता है (PEP 765) — `finally` में `return` न लिखें।

### कई एक्सेप्शन एक साथ

अलग-अलग प्रकारों के लिए कई `except` ब्लॉक लिखे जा सकते हैं, या प्रकारों को टपल में दिया जा सकता है:

```
try:
    amount = int(data["amount"])
except KeyError:
    amount = 0
except (ValueError, TypeError) as e:
    print("ख़राब रकम:", e)
    amount = 0
```

ब्लॉक ऊपर से नीचे जाँचे जाते हैं, और पहला मेल खाने वाला चलता है, इसलिए ज़्यादा ख़ास प्रकार ऊपर रखें। Python 3.14 (PEP 758) से कई प्रकार बिना कोष्ठक के भी लिखे जा सकते हैं — `except ValueError, TypeError:` — पर अगर `as` हो, तो कोष्ठक अब भी ज़रूरी हैं।

### एरर का संदेश और प्रकार कैसे देखें

एक्सेप्शन ऑब्जेक्ट `as e` से मिलता है। `str(e)` संदेश देता है, और `type(e).__name__` प्रकार का नाम:

```
try:
    int("सौ")
except ValueError as e:
    print(type(e).__name__)   # ValueError
    print(e)                  # invalid literal for int() with base 10: 'सौ'
```

## traceback मॉड्यूल: पूरा एरर-टेक्स्ट

कभी-कभी एरर पकड़नी होती है, पर पूरा traceback लॉग या रिपोर्ट के लिए सहेजना होता है। इसके लिए `traceback` मॉड्यूल है:

```
import traceback

try:
    1 / 0
except ZeroDivisionError:
    traceback.print_exc()             # stderr में traceback छापता है
    text = traceback.format_exc()     # वही टेक्स्ट स्ट्रिंग में
```

अगर `logging` मॉड्यूल से लॉग लिखते हैं, तो `except` के भीतर `logging.exception("राशि की गणना नहीं हो सकी")` लिखना आसान है — traceback अपने-आप संदेश के साथ जुड़ जाता है।

## Python raise: एक्सेप्शन खुद उठाना

स्टेटमेंट `raise` एक्सेप्शन को हाथ से उठाता है। इससे फ़ंक्शन बताता है कि ऐसे डेटा के साथ वह काम नहीं कर सकता:

```
def add_expense(amount):
    if amount < 0:
        raise ValueError(f"राशि ऋणात्मक नहीं हो सकती: {amount}")
    ...

add_expense(-5)
# ValueError: राशि ऋणात्मक नहीं हो सकती: -5
```

Python raise एक फ़ंक्शन नहीं, स्टेटमेंट है, इसलिए `raise` के बाद कोष्ठक की ज़रूरत नहीं: कोष्ठक में एक्सेप्शन के कंस्ट्रक्टर को आर्गुमेंट दिए जाते हैं। प्रकार अर्थ के हिसाब से चुनें: गलत मान हो तो `ValueError`, गलत प्रकार हो तो `TypeError`।

### बिना आर्गुमेंट का raise और raise from

`except` के भीतर अकेला `raise` मौजूदा एक्सेप्शन को बिना बदले आगे भेज देता है। यह तब काम आता है, जब आप लॉग में कुछ लिखना चाहते हैं, पर संभालना ऊपर वाले कोड पर छोड़ना चाहते हैं।

अगर एक एक्सेप्शन को दूसरे से बदलना है, तो `raise ... from e` लिखें — मूल एरर श्रृंखला में बनी रहती है, और traceback में दोनों दिखते हैं:

```
def load_config(path):
    try:
        with open(path) as f:
            return f.read()
    except FileNotFoundError as e:
        raise RuntimeError(f"कॉन्फ़िग नहीं मिली: {path}") from e
```

### add_note: एरर में संदर्भ जोड़ना

Python 3.11 (PEP 678) से एक्सेप्शन में `add_note()` मेथड से नोट जोड़ा जा सकता है और फिर उसे आगे उठाया जा सकता है। प्रकार नहीं बदलता, और नोट संदेश के नीचे छपता है:

```
def parse(raw, line_no):
    try:
        return float(raw)
    except ValueError as e:
        e.add_note(f"फ़ाइल expenses.csv, पंक्ति {line_no}")
        raise

parse("सौ", 17)
# ValueError: could not convert string to float: 'सौ'
# फ़ाइल expenses.csv, पंक्ति 17
```

## अपना एक्सेप्शन कैसे बनाएँ

अपने एक्सेप्शन विषय-क्षेत्र की गलतियों के लिए चाहिए: बजट पार हो गया, ऑर्डर पहले ही भुगतान हो चुका है, उपयोगकर्ता ब्लॉक है। इसके लिए `Exception` का उत्तराधिकारी क्लास काफ़ी है:

```
class BudgetExceeded(Exception):
    def __init__(self, category, limit, spent):
        super().__init__(f"{category}: सीमा {limit}, ख़र्च {spent}")
        self.category = category
        self.limit = limit
        self.spent = spent

def check_budget(category, limit, spent):
    if spent > limit:
        raise BudgetExceeded(category, limit, spent)

try:
    check_budget("खाना", 10000, 12500)
except BudgetExceeded as e:
    print("चेतावनी:", e)   # चेतावनी: खाना: सीमा 10000, ख़र्च 12500
```

अब कॉल करने वाला कोड ठीक बजट के पार होने को पकड़ता है और उसे टाइपो से अलग रखता है। बड़े प्रोजेक्ट में एक साझा बेस क्लास (`class TrackerError(Exception)`) बनाना सुविधाजनक है, और सारे अपने एक्सेप्शन उससे लें — तब एक `except TrackerError` से सब पकड़े जा सकते हैं। उत्तराधिकारी `Exception` से लें, `BaseException` से नहीं।

## एक्सेप्शन ग्रुप और except*

कभी-कभी एक साथ कई एरर होती हैं — जैसे पूरी फ़ाइल जाँचते समय, या `asyncio.TaskGroup` के समानांतर कार्यों में। Python 3.11 से उन्हें `ExceptionGroup` में इकट्ठा किया जा सकता है, और प्रकार के अनुसार `except*` से संभाला जा सकता है:

```
def check_all(rows):
    errors = []
    for r in rows:
        try:
            float(r)
        except ValueError as e:
            errors.append(e)
    if errors:
        raise ExceptionGroup("फ़ाइल में त्रुटियाँ", errors)

try:
    check_all(["1", "a", "b"])
except* ValueError as eg:
    print(f"ख़राब पंक्तियाँ: {len(eg.exceptions)}")   # ख़राब पंक्तियाँ: 2
```

## Python try except सारी एरर पर: ऐसा क्यों न करें

सबसे नुकसानदेह आदत है सब कुछ पकड़ना: `except: pass`। प्रोग्राम «गिरना» बंद कर देता है, पर असल में समस्याओं की ख़बर देना बंद कर देता है। खाली `except` `KeyboardInterrupt` और `SystemExit` तक पकड़ लेता है, इसलिए Ctrl+C से प्रोग्राम रोकना मुश्किल हो जाता है। `except Exception: pass` थोड़ा बेहतर है, पर वह भी नाम के टाइपो और तर्क की गलतियों को चुपचाप निगल जाता है।

एक्सेप्शन सही तरीके से कैसे संभालें:

- सिर्फ़ वही प्रकार पकड़ें, जिसे आप संभाल सकते हैं: `except ValueError`, सब कुछ नहीं;
- `try` ब्लॉक छोटा रखें — सिर्फ़ वे पंक्तियाँ जो ठीक उसी तरह गिर सकती हैं;
- अगर शीर्ष स्तर पर चौड़ा पकड़ते हैं (`except Exception`), तो traceback लॉग करना ज़रूरी है;
- जहाँ साधारण जाँच काफ़ी हो, वहाँ एक्सेप्शन को सामान्य शाखा की तरह न बरतें: सरल मामलों में `try/except KeyError` की जगह `dict.get()`;
- संसाधनों के लिए `with` लें — वह एरर होने पर भी फ़ाइल बंद कर देता है।

## निष्कर्ष

Python के एक्सेप्शन एरर बताने का सामान्य तंत्र हैं, उन्हें छिपाने का साधन नहीं। traceback नीचे से ऊपर पढ़ें, `try/except` में ख़ास प्रकार पकड़ें, `else` को «सब ठीक रहा» वाले कोड के लिए और `finally` को सफ़ाई के लिए लें। Python raise से आप खुद एरर उठाते हैं, `raise from` और `add_note` संदर्भ बचाते हैं, और अपने एक्सेप्शन `Exception` से बनते हैं। कोर्स में यह विषय व्यवहार में सिखाया जाता है: ख़र्च ट्रैकर CSV की एक ख़राब पंक्ति से नहीं गिरता, और बजट पार होने को अपने एक्सेप्शन से बताता है।

## FAQ

**एरर और एक्सेप्शन में Python में क्या फ़र्क है?**

बोलचाल में ये समानार्थी हैं। तकनीकी रूप से SyntaxError कोड पढ़ते समय ही मिल जाता है, और बाक़ी एरर चलने के दौरान एक्सेप्शन ऑब्जेक्ट के रूप में उठती हैं, जिन्हें पकड़ा जा सकता है।

**एक्सेप्शन के बाद उसी जगह से चलना जारी रह सकता है क्या?**

नहीं। पकड़ने के बाद प्रोग्राम try/except के बाद से चलता है, उस पंक्ति से नहीं जहाँ एरर आई। अगर फ़ाइल की हर पंक्ति संभालनी है, तो try को लूप के भीतर रखें।

**अगर except के भीतर एक्सेप्शन उठ जाए तो क्या होगा?**

वह आगे उठेगा, और मूल एक्सेप्शन उसके __context__ एट्रिब्यूट में सुरक्षित रहेगा। traceback में यह संदेश दिखेगा: During handling of the above exception, another exception occurred.

**टेस्ट में कैसे जाँचें कि फ़ंक्शन एक्सेप्शन उठाता है?**

pytest में with pytest.raises(ValueError): लिखें, और unittest में self.assertRaises(ValueError)। टेस्ट तभी पास होगा, जब ब्लॉक के भीतर सही प्रकार का एक्सेप्शन उठे।

**assert क्या है और raise से कैसे अलग है?**

assert शर्त, "संदेश" तब AssertionError उठाता है जब शर्त ग़लत हो। यह विकास के दौरान जाँच का औज़ार है: -O फ़्लैग से चलाने पर assert बंद हो जाते हैं, इसलिए उपयोगकर्ता का इनपुट if और raise से जाँचें।


---
Source: Skillaria.Top (https://skillaria.top)
