# Exceptions katika Python: try, except, else, finally, raise na exceptions zako mwenyewe

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

Exception katika Python ni kitu kinachoashiria kosa na kusimamisha mtiririko wa kawaida wa msimbo hadi kishughulikiaji cha try/except kiupate; else hutekelezwa kama hakukuwa na kosa, na finally hutekelezwa kila mara. Kosa linaweza kuinuliwa mwenyewe kwa amri raise, kwa mfano raise ValueError("kiasi ni hasi"), na exception yako mwenyewe huundwa kwa darasa linalorithi kutoka Exception.

Exception katika Python ni kitu kinachoashiria kosa na kusimamisha mtiririko wa kawaida wa programu. Ikiwa hakuna aliyeikamata, Python huchapisha traceback na kumaliza kazi. Exceptions hukamatwa kwa muundo wa `try/except`, na huinuliwa kwa amri `raise`. Hebu tuchunguze jinsi hili linavyofanya kazi, ni makosa gani yanayotokea mara nyingi, na jinsi ya kushughulikia makosa bila kuyaficha.

## Exception katika Python ni nini

Operesheni inaposhindwa kutekelezwa — kugawanya kwa sifuri, kufikia ufunguo usiokuwepo kwenye kamusi, kubadilisha neno kuwa namba — Python huunda kitu cha exception na kukitupa. Kazi ya sasa inasimama, exception inapanda kupitia mnyororo wa miito hadi ikutane na kishughulikiaji kinachofaa. Usipokutana nacho, programu inaanguka.

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

Jibu la swali linaloulizwa mara nyingi: kugawanya kwa sifuri katika Python kunasababisha exception `ZeroDivisionError`. Hii inahusu `/`, `//` na `%`.

## Jinsi ya kusoma traceback

Traceback ni ripoti ya jinsi programu ilivyofika kwenye kosa. Ni rahisi kuisoma kutoka chini kwenda juu. Mstari wa mwisho ndio muhimu zaidi: aina ya exception na ujumbe. Juu yake kuna mstari wa msimbo ambapo kosa lilitokea, na juu zaidi — aliyeuita, na hivyo hadi mahali pa kuingia.

```
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: 'mia'
```

Kuanzia Python 3.11 chini ya mstari wa msimbo huchorwa alama `~~~^^^` (PEP 657): zinaonyesha ni usemi upi hasa kwenye mstari ulioharibika. Hii inasaidia sana pale ambapo mstari mmoja una miito kadhaa mfululizo.

### Mapendekezo ya "Did you mean"

Kuanzia Python 3.10, kosa la jina lenye herufi zilizopotoshwa linapendekeza jina lililo karibu. Katika Python 3.15 mapendekezo yamekuwa bora zaidi: mkalimani anajua tabia kutoka lugha nyingine. Mwito wa `list.push` utapendekeza `append`, na `"kahawa".toUpperCase()` — mbinu `upper`. Pendekezo pia linaangalia sehemu zilizoingizwa ndani: ikiwa kamusi iko kwenye sifa `totals` ya kitu, na umeita `items()` moja kwa moja kwenye kitu, kosa litapendekeza `.totals.items`. Majina yaliyo karibu sasa pia hupendekezwa na `delattr()`.

## Aina za exceptions katika Python

Exceptions zilizojengwa ndani ni dazeni, lakini mwanzoni utakutana zaidi na hizi:

| Exception | Inatokea lini | Mfano |
| --- | --- | --- |

| `NameError` | Jina halijafafanuliwa, mara nyingi ni kosa la kuandika | `print(totl)` |

| `TypeError` | Operesheni haifai kwa aina hiyo | `"5" + 3` |

| `ValueError` | Aina ni sahihi, thamani si sahihi | `int("mia")` |

| `KeyError` | Hakuna ufunguo huo kwenye kamusi | `d["missing"]` |

| `IndexError` | Faharasa nje ya orodha | `[1, 2][5]` |

| `AttributeError` | Kitu hakina mbinu au sehemu hiyo | `[].push(1)` |

| `ZeroDivisionError` | Kugawanya kwa sifuri | `1 / 0` |

| `FileNotFoundError` | Faili halijapatikana | `open("nope.txt")` |

Kuna `SyntaxError` (na kesi yake maalum `IndentationError`): hutokea tayari wakati faili linachambuliwa, kabla msimbo haujaendeshwa, kwa hiyo haiwezi kukamatwa kwa `try` katika faili hilohilo.

### Mpangilio wa exceptions

Exceptions ni madarasa, na yamepangwa katika mpangilio wa urithi. Juu kabisa kuna `BaseException`. Kutoka hapo wanarithi `Exception` (karibu makosa yote ya kawaida) na zile za mfumo: `KeyboardInterrupt`, `SystemExit`, `GeneratorExit`.

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

Mpangilio huu ni muhimu unapokamata: `except LookupError` itakamata `KeyError` na `IndexError`. Na `KeyboardInterrupt` si kosa la msimbo: hivyo Python inaonyesha kwamba mtumiaji amebonyeza Ctrl+C. Haitokani na `Exception` kwa makusudi, ili `except Exception` isizuie kusimamisha programu.

## Kushughulikia exceptions: try/except/else/finally

Msimbo ambao unaweza kuanguka huwekwa kwenye kizuizi cha `try`. Katika `except` unataja aina ya kosa na nini cha kufanya nalo. Ni `except` ndicho kizuizi ambacho Python hutumia kushughulikia exceptions.

```
def parse_amount(raw):
    try:
        value = float(raw)
    except ValueError as e:
        print(f"Ninaruka mstari: {e}")
        return None
    else:
        return value          # hutekelezwa ikiwa hakukuwa na kosa
    finally:
        print("uchambuzi umekamilika")   # hutekelezwa kila mara

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

Hapa mpangilio wa matokeo ni: kwanza "uchambuzi umekamilika", kisha `250.0`. `return` ndani ya `else` inakumbuka thamani, kisha Python lazima itekeleze `finally` na ndipo irudishe matokeo. Kwa hiyo `finally` inaaminika kwa usafishaji: kufunga faili, kuachilia muunganisho.

Ukiandika `return` yako mwenyewe ndani ya `finally`, itafuta ile ya awali na hata "kumeza" exception. Kuanzia Python 3.14 msimbo kama huo unatoa `SyntaxWarning` (PEP 765) — usiandike `return` ndani ya `finally`.

### Exceptions kadhaa kwa mara moja

Unaweza kuandika vizuizi kadhaa vya `except` kwa aina tofauti, au kuorodhesha aina kwenye tuple:

```
try:
    amount = int(data["amount"])
except KeyError:
    amount = 0
except (ValueError, TypeError) as e:
    print("Kiasi si sahihi:", e)
    amount = 0
```

Vizuizi hukaguliwa kutoka juu kwenda chini, na la kwanza linalofaa ndilo linalotekelezwa, kwa hiyo aina mahususi huwekwa juu ya zile za jumla. Kuanzia Python 3.14 (PEP 758) aina kadhaa zinaweza kuorodheshwa bila mabano — `except ValueError, TypeError:` — lakini ikiwa kuna `as`, mabano bado yanahitajika.

### Jinsi ya kuonyesha ujumbe wa kosa na kujua aina yake

Kitu cha exception kinapatikana kupitia `as e`. `str(e)` hutoa ujumbe, na `type(e).__name__` hutoa jina la aina:

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

## Moduli ya traceback: maandishi kamili ya kosa

Wakati mwingine kosa linahitaji kukamatwa lakini traceback kamili ihifadhiwe — kwa logi au ripoti. Kwa hilo kuna moduli `traceback`:

```
import traceback

try:
    1 / 0
except ZeroDivisionError:
    traceback.print_exc()             # inachapisha traceback kwenye stderr
    text = traceback.format_exc()     # maandishi hayohayo kama mfuatano
```

Ikiwa unaandika logi kwa moduli `logging`, ni rahisi kuita `logging.exception("imeshindwa kuhesabu")` ndani ya `except` — traceback itaongezwa kwenye ujumbe moja kwa moja.

## Python raise: jinsi ya kuinua exception

Amri `raise` inatupa exception kwa mkono. Kwa njia hii kazi inaeleza kwamba haiwezi kufanya kazi na data kama hizo:

```
def add_expense(amount):
    if amount < 0:
        raise ValueError(f"Kiasi hakiwezi kuwa hasi: {amount}")
    ...

add_expense(-5)
# ValueError: Kiasi hakiwezi kuwa hasi: -5
```

Python raise ni amri, si kazi, kwa hiyo hakuna haja ya mabano baada ya neno `raise`: ndani ya mabano unapitisha hoja za konstrukta ya exception. Chagua aina kwa maana yake: thamani isiyo sahihi ni `ValueError`, aina isiyo sahihi ni `TypeError`.

### raise bila hoja na raise from

Ndani ya `except`, `raise` tupu hupeleka mbele exception ya sasa bila mabadiliko. Hii inahitajika ukitaka kuandika kitu kwenye logi lakini uache ushughulikiaji kwa msimbo wa mwito.

Ukibadilisha exception moja na nyingine, tumia `raise ... from e` — kosa la asili linabaki kwenye mnyororo, na traceback inaonyesha zote mbili:

```
def load_config(path):
    try:
        with open(path) as f:
            return f.read()
    except FileNotFoundError as e:
        raise RuntimeError(f"Hakuna config {path}") from e
```

### add_note: kuongeza muktadha kwenye kosa

Kuanzia Python 3.11 (PEP 678) unaweza kuongeza maelezo kwenye exception kwa mbinu `add_note()` na kuendelea kuirusha. Aina ya kosa haibadiliki, na maelezo yanachapishwa chini ya ujumbe:

```
def parse(raw, line_no):
    try:
        return float(raw)
    except ValueError as e:
        e.add_note(f"faili expenses.csv, mstari {line_no}")
        raise

parse("mia", 17)
# ValueError: could not convert string to float: 'mia'
# faili expenses.csv, mstari 17
```

## Jinsi ya kuunda exception yako katika Python

Exceptions zako mwenyewe zinahitajika kwa makosa ya eneo la biashara: bajeti imezidi, agizo tayari limelipwa, mtumiaji amezuiwa. Inatosha kuwa na darasa linalorithi `Exception`:

```
class BudgetExceeded(Exception):
    def __init__(self, category, limit, spent):
        super().__init__(f"{category}: kikomo {limit}, kimetumika {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("Chakula", 10000, 12500)
except BudgetExceeded as e:
    print("Onyo:", e)   # Onyo: Chakula: kikomo 10000, kimetumika 12500
```

Sasa msimbo wa mwito unakamata hasa kuzidi kwa bajeti, na hauchanganyi na makosa ya kuandika. Katika mradi mkubwa ni vizuri kuwa na darasa la msingi la pamoja (`class TrackerError(Exception)`) na kurithi exceptions zako zote kutoka humo — basi zote zinaweza kukamatwa kwa `except TrackerError` moja. Rithi kutoka `Exception`, si kutoka `BaseException`.

## Vikundi vya exceptions na except*

Wakati mwingine kuna makosa kadhaa kwa wakati mmoja — kwa mfano wakati wa kukagua faili zima, au katika kazi sambamba za `asyncio.TaskGroup`. Kuanzia Python 3.11 yanaweza kukusanywa kwenye `ExceptionGroup`, na kushughulikiwa kwa aina kupitia `except*`:

```
def check_all(rows):
    errors = []
    for r in rows:
        try:
            float(r)
        except ValueError as e:
            errors.append(e)
    if errors:
        raise ExceptionGroup("makosa katika faili", errors)

try:
    check_all(["1", "a", "b"])
except* ValueError as eg:
    print(f"Mistari yenye hitilafu: {len(eg.exceptions)}")   # Mistari yenye hitilafu: 2
```

## Python try except kwa makosa yote: kwa nini hilo si wazo zuri

Tabia mbaya zaidi ni kukamata kila kitu: `except: pass`. Programu "inaacha kuanguka", lakini kwa kweli inaacha kuripoti matatizo. `except` tupu hukamata hata `KeyboardInterrupt` na `SystemExit`, kwa hiyo programu haisimamishwi kwa Ctrl+C. `except Exception: pass` ni bora kidogo, lakini bado inameza kimya makosa ya kuandika majina na makosa ya mantiki.

Jinsi ya kushughulikia exceptions kwa usahihi katika Python:

- kamata aina ile tu unayoweza kuishughulikia: `except ValueError`, si kila kitu;
- weka kizuizi cha `try` kifupi — mistari tu inayoweza kuanguka kwa namna hiyo;
- ukikamata kwa upana (`except Exception`) kwenye ngazi ya juu ya programu, hakikisha unaandika traceback kwenye logi;
- usitumie exceptions kwa matawi ya kawaida pale ukaguzi unatosha: `dict.get()` badala ya `try/except KeyError` katika kesi rahisi;
- kwa rasilimali tumia `with` — yenyewe itafunga faili hata kukiwa na kosa.

## Hitimisho

Exceptions katika Python ni utaratibu wa kawaida wa kuripoti makosa, si sababu ya kuyaficha. Soma traceback kutoka chini kwenda juu, kamata aina mahususi kwa `try/except`, tumia `else` kwa msimbo wa "kila kitu kimeenda sawa" na `finally` kwa usafishaji. Python raise inakuwezesha kuripoti kosa mwenyewe, `raise from` na `add_note` zinahifadhi muktadha, na exceptions zako zinarithi kutoka `Exception`. Katika kozi ya Python mada hii inafundishwa kwa vitendo: kifuatiliaji cha matumizi kinaacha kuanguka kwa sababu ya mstari mmoja mbaya wa CSV, na kinaeleza kuzidi kwa bajeti kwa exception yake mwenyewe.

## FAQ

**Kosa linatofautianaje na exception katika Python?**

Kwa lugha ya kawaida ni kitu kimoja. Kiufundi, SyntaxError hugunduliwa tayari wakati wa kuchambua msimbo, huku makosa mengine yanatokea wakati wa utekelezaji kama vitu vya exception vinavyoweza kukamatwa.

**Je, naweza kuendelea na utekelezaji kutoka mahali kosa lilipotokea?**

Hapana. Baada ya kukamata, utekelezaji unaendelea baada ya kizuizi cha try/except, si kutoka mstari uliosababisha kosa. Ikiwa unataka kushughulikia kila mstari wa faili, weka try ndani ya mzunguko.

**Itakuwaje kosa likitokea ndani ya except?**

Litapanda zaidi, na exception ya asili itahifadhiwa kwenye sifa yake __context__. Kwenye traceback itaonekana maneno During handling of the above exception, another exception occurred.

**Ninawezaje kukagua kwenye majaribio kwamba kazi inatupa exception?**

Kwenye pytest tumia with pytest.raises(ValueError):, na kwenye unittest — self.assertRaises(ValueError). Jaribio litapita tu ikiwa ndani ya kizuizi kumetokea exception ya aina sahihi.

**assert ni nini na inatofautianaje na raise?**

assert sharti, "ujumbe" hutupa AssertionError sharti likiwa si kweli. Ni zana ya ukaguzi wakati wa maendeleo: ikiendeshwa kwa bendera -O, assert zinazimwa, kwa hiyo ingizo la mtumiaji linapaswa kukaguliwa kwa if na raise.


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