# Python-இல் விதிவிலக்குகள் (exceptions): try, except, else, finally, raise மற்றும் சொந்த விதிவிலக்குகள்

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

Python-இல் exception என்பது பிழையைக் குறிக்கும் பொருள்; அது try/except தொகுதியால் பிடிக்கப்படும் வரை வழக்கமான இயக்கத்தை நிறுத்துகிறது. else பிழை இல்லாதபோது இயங்கும், finally எப்போதும் இயங்கும். raise கட்டளையால் நாமே exception-ஐ எழுப்பலாம், எடுத்துக்காட்டாக raise ValueError("தொகை எதிர்மறை"); சொந்த exception Exception-இன் துணைவகுப்பால் உருவாக்கப்படுகிறது.

Python-இல் exception என்பது பிழையைச் சமிக்ஞை செய்து சாதாரண நிரல் ஓட்டத்தை நிறுத்தும் பொருள். யாரும் பிடிக்கவில்லையென்றால் Python traceback-ஐ அச்சிட்டு நிரலை முடிக்கும். `try/except` கட்டமைப்பால் அவற்றைப் பிடிக்கிறோம்; `raise` கட்டளையால் நாமே எழுப்புகிறோம். இது எப்படி அமைந்துள்ளது, எந்தப் பிழைகள் அடிக்கடி வருகின்றன, பிழை கையாளுதலை பிழைகளை மறைப்பதாக மாற்றாமல் எப்படி எழுதுவது என்று பார்ப்போம்.

## Python-இல் exception என்றால் என்ன

ஒரு செயல்பாடு நிறைவேற முடியாதபோது — பூஜ்ஜியத்தால் வகுத்தல், இல்லாத விசையை அணுகுதல், சொல்லை எண்ணாக மாற்றுதல் — Python ஒரு exception பொருளை உருவாக்கி "எழுப்புகிறது". தற்போதைய செயல்பாடு நிற்கும், விதிவிலக்கு அழைப்புச் சங்கிலியின் வழியே மேலே ஏறும், பொருத்தமான கையாளுநரைக் கண்டறியும் வரை. கிடைக்கவில்லையென்றால் நிரல் விழுகிறது.

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

அடிக்கடி கேட்கப்படும் கேள்விக்கு பதில்: Python-இல் பூஜ்ஜியத்தால் வகுக்கும்போது `ZeroDivisionError` எழுகிறது. இது `/`, `//` மற்றும் `%` மூன்றுக்கும் பொருந்தும்.

## Traceback-ஐ எப்படிப் படிப்பது

Traceback என்பது நிரல் பிழையை அடைந்த வழியின் அறிக்கை. அதை கீழிருந்து மேலாகப் படிப்பது எளிது. கடைசி வரி முக்கியம்: exception-இன் வகையும் செய்தியும். அதற்கு மேல் பிழை நடந்த குறியீட்டு வரி, அதற்கு மேல் அதை அழைத்தது யார் — நுழைவுப் புள்ளி வரை.

```
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` குறியீட்டின் பிழை அல்ல: பயனர் Ctrl+C அழுத்தியதை Python இப்படித்தான் தெரிவிக்கிறது. அது வேண்டுமென்றே `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` தொகுதிகளை எழுதலாம், அல்லது வகைகளை ஒரு tuple-இல் பட்டியலிடலாம்:

```
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` இருந்தால் அடைப்புகள் இன்னும் தேவை.

### பிழைச் செய்தியையும் அதன் வகையையும் அறிவது

Exception பொருள் `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()             # traceback-ஐ stderr-க்கு அச்சிடும்
    text = traceback.format_exc()     # அதே உரை சரமாக
```

`logging` தொகுதி மூலம் பதிவு எழுதினால், `except`-க்குள் `logging.exception("கணக்கிட முடியவில்லை")` அழைப்பது எளிது — traceback செய்தியுடன் தானாகச் சேர்க்கப்படும்.

## Python raise: விதிவிலக்கை எழுப்புவது

`raise` கட்டளை exception-ஐ கைமுறையாக எழுப்புகிறது. அப்படித்தான் ஒரு செயல்பாடு இத்தகைய தரவுடன் வேலை செய்ய முடியாது என்று அறிவிக்கிறது:

```
def add_expense(amount):
    if amount < 0:
        raise ValueError(f"தொகை எதிர்மறையாக இருக்க முடியாது: {amount}")
    ...

add_expense(-5)
# ValueError: தொகை எதிர்மறையாக இருக்க முடியாது: -5
```

Python raise ஒரு செயல்பாடல்ல, ஒரு கட்டளை; அதனால் `raise` என்ற சொல்லுக்குப் பின் அடைப்புகள் தேவையில்லை: அடைப்புக்குள் அனுப்பப்படுவது exception கட்டமைப்பிக்குரிய வாதங்கள். வகையைப் பொருளின்படித் தேர்ந்தெடுங்கள்: தவறான மதிப்பு — `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) exception-க்கு `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
```

## Python-இல் சொந்த exception உருவாக்குவது

சொந்த விதிவிலக்குகள் துறையின் பிழைகளுக்குத் தேவை: பட்ஜெட் மீறப்பட்டது, ஆர்டர் ஏற்கனவே செலுத்தப்பட்டது, பயனர் தடுக்கப்பட்டார். `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`-இலிருந்து அல்ல.

## Exception குழுக்கள் மற்றும் 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` சற்று மேல்தான், ஆனால் அதுவும் பெயர் எழுத்துப்பிழைகளையும் தர்க்கப் பிழைகளையும் அமைதியாக விழுங்கும்.

Python-இல் விதிவிலக்குகளை சரியாகக் கையாள:

- கையாளத் தெரிந்த வகையை மட்டும் பிடியுங்கள்: `except ValueError`, எல்லாவற்றையும் அல்ல;
- `try` தொகுதியை சிறியதாக வையுங்கள் — அப்படித்தான் விழக்கூடிய வரிகள் மட்டும் அதில் இருக்கும்;
- நிரலின் மேல் நிலையில் பரந்த பிடிப்பு (`except Exception`) பயன்படுத்தினால், traceback-ஐ கட்டாயம் பதிவு செய்யுங்கள்;
- எளிய சரிபார்ப்பு போதுமானதாக இருக்கும் இடத்தில் விதிவிலக்குகளை சாதாரண கிளைக்கு பயன்படுத்தாதீர்கள்: எளிய நிலைகளில் `try/except KeyError`-க்குப் பதிலாக `dict.get()`;
- வளங்களுக்கு `with`-ஐ விரும்புங்கள் — பிழை வந்தாலும் அது கோப்பை மூடிவிடும்.

## சுருக்கம்

Python-இல் exceptions பிழைகளைத் தெரிவிக்கும் சாதாரண வழிமுறை, அவற்றை மறைக்க அல்ல. Traceback-ஐ கீழிருந்து மேலாகப் படியுங்கள், `try/except`-இல் குறிப்பான வகைகளைப் பிடியுங்கள், வெற்றிக்கான குறியீட்டுக்கு `else`-ஐயும், சுத்தம் செய்வதற்கு `finally`-ஐயும் பயன்படுத்துங்கள். Python raise பிழையை நாமே தெரிவிக்க உதவும்; `raise from` மற்றும் `add_note` சூழலைப் பாதுகாக்கும்; சொந்த விதிவிலக்குகள் `Exception`-இலிருந்து மரபுரிமை பெறும். Python பாடநெறியில் இந்தத் தலைப்பு நடைமுறையில் விளக்கப்பட்டுள்ளது: செலவு கண்காணிப்பான் ஒரு தவறான CSV வரியால் விழுவதில்லை, பட்ஜெட் மீறலை அதன் சொந்த விதிவிலக்கால் வெளிப்படுத்துகிறது.

## FAQ

**பிழைக்கும் விதிவிலக்குக்கும் என்ன வேறுபாடு Python-இல்?**

பேச்சு வழக்கில் இவை ஒத்த சொற்கள். தொழில்நுட்ப ரீதியாக SyntaxError குறியீட்டை அலசும்போதே கண்டறியப்படுகிறது; மற்ற பிழைகள் இயக்கத்தின்போது பிடிக்கக்கூடிய exception பொருள்களாக எழுகின்றன.

**விதிவிலக்கு நிகழ்ந்த அதே இடத்திலிருந்து நிரலைத் தொடர முடியுமா?**

இல்லை. பிடித்த பின் இயக்கம் try/except தொகுதிக்குப் பின்னால் தொடரும், பிழை நடந்த வரியிலிருந்து அல்ல. கோப்பின் ஒவ்வொரு வரியையும் கையாள வேண்டுமென்றால் try-ஐ சுழலுக்குள் வையுங்கள்.

**<code>except</code>-க்குள் விதிவிலக்கு எழுந்தால் என்ன ஆகும்?**

அது மேலே செல்லும்; அசல் விதிவிலக்கு புதியதன் __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)
