---
title: İstisnalar
source: 'https://academia.sh/tr/kurslar/python-temelleri/istisnalar'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:27+00:00'
license: 'CC BY-SA 4.0'
---

# İstisnalar

İstisna bir sınıfın örneğidir ve yakalama sınıf soyağacına bakar; on bir olay ile yedi yakalama sınıfı 77 çiftin 28'inde tutar, Exception on olayı yakalayıp üç program kusurunu yutar, BaseException on biri de yakalayıp çıkış isteğini de yutar.

Buraya kadar ölçülen her protokol beklenen yolu izledi. `for` yineleyiciyi istedi ve aldı,
`len` bir sayı döndürdü, `sorted` sıralanmış bir liste verdi. Sözdizim çağırdı, özel yöntem
karşılık verdi, değer geri döndü. Peki bir protokol **başarısız olursa** ne olur?

Python'un yanıtı, önceki dersin döngü ölçümünde çoktan görüldü: üç öğelik nesnede dördüncü
`__next__` çağrısı bir değer döndürmez, **`StopIteration` fırlatır**. Döngüyü bitiren şey bir
dönüş değeri değil, bir istisnadır. Bu ders o düzeneğin kendisine bakar. **İstisna kavramı**
ve hata yönetimi Programlama Temelleri kursunda kuruldu; orada **kavram** kuruldu, burada
Python'un onu hangi düzenekle gerçekleştirdiği ölçülüyor: istisna bir nesnedir, nesnenin bir
sınıfı vardır ve **yakalama o sınıfın soyağacına bakar**.

## İstisna Bir Sınıfın Örneğidir

Fırlatılan şey bir ileti değil, bir **nesnedir**. `raise` deyimi bir nesne alır, `except`
deyimi bir **sınıf** alır ve ikisi `isinstance` ile karşılaştırılır. Bu tek cümle dersin
geri kalanını belirler: `except` bir sınıf adı yazdığı için, o sınıfın **bütün alt
sınıfları** da yakalanır.

Soyağacı iki uçtan başlar. Her istisna sınıfı `BaseException`'dan türer. Onun hemen altında
`Exception` durur ve program içinde ele alınması beklenen her şey oradan iner. `Exception`'ın
altında ara sınıflar vardır — `ArithmeticError`, `LookupError`, `OSError` — ve yaprakları
`ZeroDivisionError`, `KeyError`, `FileNotFoundError` gibi somut sınıflardır.

Bu ara sınıflar boş süs değildir. Bir yaprağı yakalamak yalnız onu yakalar; ara sınıfı
yakalamak **altındaki bütün yaprakları** yakalar. Kaç tanesini yakaladığı ölçülebilir bir
sayıdır ve bu dersin ölçtüğü sayı odur.

## Ölçümün Kurgusu

Ölçüm on bir **olay** kurar: her biri gerçekten bir istisna fırlatan küçük bir işlev. Karşısına
yedi **yakalama sınıfı** konur — iki yaprak, üç ara sınıf ve iki kök. Her olay her yakalama
sınıfıyla denenir; sonuç 77 çiftlik bir tablodur.

Olaylar üç etikete ayrılır ve etiket **kâhindir**: kurguyu biz kurduğumuz için hangi olayın
gerçekten bir **alan hatası**, hangisinin bir **program kusuru**, hangisinin bir **kesinti**
olduğunu biliriz. Alan hatası ele alınması beklenen şeydir — eksik anahtar, çevrilemeyen
dizgi, bulunamayan dosya. Program kusuru kodun kendisindeki yanlıştır ve ele alınması değil,
**dışarı çıkması** gerekir. Kesinti programın bitirilmesi isteğidir ve yutulmamalıdır.
`StopIteration` dördüncü bir etikettir: hata değil, **protokolün parçasıdır**.

Ölçümün varsayımları:

- **HD1** — On bir olayın hepsi gerçekten çalıştırılır ve fırlattıkları nesne yakalanıp
  saklanır; hiçbir sınıf adı elle yazılmaz, tablodaki her sınıf adı **fırlatılan nesneden**
  okunur.
- **HD2** — Etiket kâhindir ve kurgunun kendisinden gelir; iletiye ya da sınıf adına bakarak
  çıkarılmaz.
- **HD3** — Bir çiftin "tuttuğu", yakalama sınıfının olayın nesnesini `isinstance` ile
  kapsaması demektir; `except` deyiminin yaptığı sınama budur.
- **HD4** — Soyağacı zinciri sınıfın çözüm sırasından okunur; `object` sayılmaz, çünkü her
  sınıf ondan iner ve ayırt edici değildir.
- **HD5** — Ölçüm bir başarım ölçümü değildir; sayılan şey **yakalanan olay adedidir**, süre
  değil.

## Ölçüm — Yakalama Matrisi

```python
"""Istisna hiyerarsisi: hangi sinifi yakalamak hangi olaylari da yakalar."""
import math

KAYIT = []


class Izci:
    """Ortak tanimin cekirdegi; burada yalniz yineleme parcasi kullaniliyor."""

    def __init__(self, ogeler=(1, 2, 3)):
        self.ogeler = list(ogeler)

    def __iter__(self):
        KAYIT.append("__iter__")
        self._i = 0
        return self

    def __next__(self):
        KAYIT.append("__next__")
        if self._i >= len(self.ogeler):
            raise StopIteration
        deger = self.ogeler[self._i]
        self._i += 1
        return deger


def sifira_bolme():
    return 1 // 0


def tasan_us():
    return math.exp(10000)


def eksik_anahtar():
    return {"kuzey": 1}["yamac"]


def tasan_dizin():
    return [1, 2, 3][9]


def cevrilemeyen_dizgi():
    return int("kuzey")


def bulunamayan_dosya():
    return open("yok/olcum.txt")


def biten_yineleyici():
    return next(iter(Izci(())))


def yanlis_tip():
    return len(5)


def olmayan_ad():
    return bilinmeyen_ad


def olmayan_oznitelik():
    return (1).kuzey


def cikis_istegi():
    raise SystemExit


OLAYLAR = (
    ("sıfıra bölme",       sifira_bolme,       "alan"),
    ("taşan üs",           tasan_us,           "alan"),
    ("eksik anahtar",      eksik_anahtar,      "alan"),
    ("taşan dizin",        tasan_dizin,        "alan"),
    ("çevrilemeyen dizgi", cevrilemeyen_dizgi, "alan"),
    ("bulunamayan dosya",  bulunamayan_dosya,  "alan"),
    ("biten yineleyici",   biten_yineleyici,   "protokol"),
    ("yanlış tip",         yanlis_tip,         "kusur"),
    ("olmayan ad",         olmayan_ad,         "kusur"),
    ("olmayan öznitelik",  olmayan_oznitelik,  "kusur"),
    ("çıkış isteği",       cikis_istegi,       "kesinti"),
)

YAKALAMALAR = (
    ("ZeroDivisionError", ZeroDivisionError),
    ("ArithmeticError",   ArithmeticError),
    ("LookupError",       LookupError),
    ("ValueError",        ValueError),
    ("OSError",           OSError),
    ("Exception",         Exception),
    ("BaseException",     BaseException),
)


def firlat(islev):
    try:
        islev()
    except BaseException as e:
        return e
    return None


print("olay                  sınıf              hiyerarşideki yeri")
for ad, islev, _ in OLAYLAR:
    s = type(firlat(islev))
    zincir = " < ".join(k.__name__ for k in s.__mro__ if k is not object)
    print(f"  {ad:19s} {s.__name__:18s} {zincir}")

print()
print("yakalama sınıfı     yakalar  alan  protokol  kusur  kesinti  kaçar")
for yad, ysinif in YAKALAMALAR:
    sayac = {"alan": 0, "protokol": 0, "kusur": 0, "kesinti": 0}
    for ad, islev, tur in OLAYLAR:
        if isinstance(firlat(islev), ysinif):
            sayac[tur] += 1
    y = sum(sayac.values())
    print(f"  {yad:18s} {y:7d} {sayac['alan']:5d} {sayac['protokol']:9d}"
          f" {sayac['kusur']:6d} {sayac['kesinti']:8d} {len(OLAYLAR) - y:6d}")

print()
tutan = sum(isinstance(firlat(i), ys)
            for _, i, _ in OLAYLAR for _, ys in YAKALAMALAR)
print(f"olay {len(OLAYLAR)} | yakalama sınıfı {len(YAKALAMALAR)} | "
      f"çift {len(OLAYLAR) * len(YAKALAMALAR)} | tutan çift {tutan}")
for etiket in ("kusur", "kesinti"):
    liste = [ad for ad, _, t in OLAYLAR if t == etiket]
    print(f"{etiket} {len(liste)}: {', '.join(liste)}")

KAYIT.clear()
firlat(biten_yineleyici)
print(f"boş Izci: {KAYIT.count('__iter__')} kez __iter__, "
      f"{KAYIT.count('__next__')} kez __next__ — o tek çağrı değer "
      f"döndürmedi, StopIteration fırlattı")
```

```
olay                  sınıf              hiyerarşideki yeri
  sıfıra bölme        ZeroDivisionError  ZeroDivisionError < ArithmeticError < Exception < BaseException
  taşan üs            OverflowError      OverflowError < ArithmeticError < Exception < BaseException
  eksik anahtar       KeyError           KeyError < LookupError < Exception < BaseException
  taşan dizin         IndexError         IndexError < LookupError < Exception < BaseException
  çevrilemeyen dizgi  ValueError         ValueError < Exception < BaseException
  bulunamayan dosya   FileNotFoundError  FileNotFoundError < OSError < Exception < BaseException
  biten yineleyici    StopIteration      StopIteration < Exception < BaseException
  yanlış tip          TypeError          TypeError < Exception < BaseException
  olmayan ad          NameError          NameError < Exception < BaseException
  olmayan öznitelik   AttributeError     AttributeError < Exception < BaseException
  çıkış isteği        SystemExit         SystemExit < BaseException

yakalama sınıfı     yakalar  alan  protokol  kusur  kesinti  kaçar
  ZeroDivisionError        1     1         0      0        0     10
  ArithmeticError          2     2         0      0        0      9
  LookupError              2     2         0      0        0      9
  ValueError               1     1         0      0        0     10
  OSError                  1     1         0      0        0     10
  Exception               10     6         1      3        0      1
  BaseException           11     6         1      3        1      0

olay 11 | yakalama sınıfı 7 | çift 77 | tutan çift 28
kusur 3: yanlış tip, olmayan ad, olmayan öznitelik
kesinti 1: çıkış isteği
boş Izci: 1 kez __iter__, 1 kez __next__ — o tek çağrı değer döndürmedi, StopIteration fırlattı
```

## Sayıların Okunması

Üst tablo soyağacını veriyor ve derinliğin sabit olmadığını gösteriyor. `ValueError` iki
adımda köke varıyor, `FileNotFoundError` üç adımda. Aradaki fark bir ayrıntı değil: her ara
adım, o adımı yakalayan bir `except` deyimine karşılık gelir.

Alt tablo bunun bedelini sayıyor. `ZeroDivisionError` yakalaması **1** olayı tutuyor ve
**10**'unu kaçırıyor. Bir adım yukarıdaki `ArithmeticError` **2** tutuyor — sıfıra bölmeyi ve
taşan üssü. `LookupError` de **2** tutuyor, eksik anahtarı ve taşan dizini. Tek bir `except`
satırı yazıp iki ayrı olayı ele almanın yolu, o iki olayın **ortak atasını** yazmaktır.

`OSError` satırı **1** gösteriyor, çünkü ölçümde ondan inen tek olay var. Sayı kurgunun
sayısıdır, sınıfın kapsamının değil: `OSError` altında çok sayıda yaprak bulunur ve hepsi bu
satıra düşerdi. Ders **kendi ölçtüğü sayıyı** yazar.

## Geniş Yakalamanın Yuttuğu

İki kök satırı tablonun asıl bulgusudur. `Exception` yakalaması **10** olayı tutuyor ve
yalnız **1**'ini kaçırıyor. Bu on olayın **6**'sı alan hatası — ele alınması beklenen şey.
Ama aynı satır **3** program kusurunu da yutuyor: yanlış tip, olmayan ad, olmayan öznitelik.
Bu üçü kullanıcı girdisinden ya da dosya sisteminden gelmez; **kodun kendisindeki
yanlıştan** gelir. `except Exception` yazan bir blok bunları da sessizce yakalar ve program
yanlış yazılmış hâliyle çalışmaya devam eder.

Bir de **1** protokol olayı yutuyor: `StopIteration`. Son satır bunun nereden geldiğini
söylüyor: boş `Izci` üzerinde **1** kez `__iter__`, **1** kez `__next__` çağrıldı ve o tek
çağrı bir değer döndürmek yerine `StopIteration` fırlattı — öğe sayısından bir fazla. Geniş
bir yakalama, bir döngünün **normal bitişini** bir hata sanıp kendi dalına düşebilir.

`BaseException` bir adım daha ileri gidiyor: **11** olayın hepsini tutuyor, kaçan **0**.
Fazladan tuttuğu tek şey **çıkış isteğidir** ve bu, dersin en keskin sayısıdır. `Exception`
onu kaçırır — kaçırması **tasarımdır**. Programın bitirilmesi isteği bir alan hatası değildir
ve ele alınacak bir şey değildir; `except BaseException` yazmak, o isteği de yutmak demektir.
İki kök satırı arasındaki tek fark budur ve tabloda **11 − 10 = 1** olarak durur.

Örüntü şudur: **yakalama sınıfı yukarı çıktıkça tuttuğu olay artar, ama tuttuklarının
yalnız bir bölümü ele alınması gereken şeydir.** 77 çiftin **28**'i tutuyor; bu 28 tutmanın
**21**'i iki kök satırından geliyor. Daraltmak, tutulan olayı azaltıp yutulanı sıfırlamaktır.

## Yeniden Fırlatma ve Neden Zinciri

Bir istisnayı yakalamak onu ele almak zorunda değildir. Yakalayıp kayıt düşmek, sonra
**yeniden fırlatmak** yaygın bir gerekliliktir ve Python bunun için birkaç ayrı biçim sunar.
Biçimler arasındaki fark, dışarı çıkan **nesnenin kimliği** ve iç nesnenin durup durmadığıdır.

Her istisna nesnesi iki alan taşır. `__context__`, o istisna başka bir istisna ele alınırken
oluştuysa **öbürüne** işaret eder ve yorumlayıcı bunu kendiliğinden kurar. `__cause__` ise
yalnız `from` yazıldığında dolar ve "bu istisnanın nedeni şudur" bildirimidir. `from None`
bağlamı **bastırır**.

- **HD6** — Beş yeniden fırlatma biçimi aynı kaynaktan üretilir; kaynak her çağrıda **yeni
  bir nesne** ürettiği için biçimler birbirinin nesnesini paylaşmaz.
- **HD7** — Nesnelerin aynı olup olmadığı `is` ile sınanır; **kimlik sayısı basılmaz**.
- **HD8** — Zincir uzunluğu, bastırılmamış bağlam ve neden bağları izlenerek sayılır; yutan
  biçimde dışarı istisna çıkmadığı için uzunluk sıfırdır.
- **HD9** — Dal tablosu üç durumu ayrı ayrı çalıştırır ve her dalın çalışıp çalışmadığı, dalın
  içine konan bir kayıttan okunur; sıra tahmin edilmez, ölçülür.

```python
"""Yeniden firlatma ve zincir: disari cikan nesne hangisi, ic nesne duruyor mu."""

ADIM = []


def kaynak():
    """Alan hatasini uretir; her cagrida yeni bir nesne olusur."""
    return {"kuzey": 1}["yamac"]


def ciplak():
    try:
        kaynak()
    except KeyError:
        raise


def sarmala():
    try:
        kaynak()
    except KeyError:
        raise RuntimeError("ölçüm okunamadı")


def nedeniyle():
    try:
        kaynak()
    except KeyError as e:
        raise RuntimeError("ölçüm okunamadı") from e


def bastir():
    try:
        kaynak()
    except KeyError:
        raise RuntimeError("ölçüm okunamadı") from None


def yut():
    try:
        kaynak()
    except KeyError:
        return None


BICIMLER = (("çıplak raise", ciplak), ("sarmalayan", sarmala),
            ("from ile", nedeniyle), ("from None ile", bastir),
            ("yutan", yut))

print(f"{'biçim':<17s}{'dışarı çıkan':<15s}{'neden':<14s}"
      f"{'bağlam':<14s}zincir")
for ad, islev in BICIMLER:
    try:
        islev()
    except BaseException as d:
        cikan = type(d).__name__
        neden = type(d.__cause__).__name__ if d.__cause__ else "-"
        baglam = type(d.__context__).__name__ if d.__context__ else "-"
        n, k = 0, d
        while k is not None:
            n += 1
            k = k.__cause__ or (None if k.__suppress_context__
                                else k.__context__)
    else:
        cikan = neden = baglam = "-"
        n = 0
    print(f"  {ad:<15s}{cikan:<15s}{neden:<14s}{baglam:<14s}{n}")

print()
try:
    try:
        kaynak()
    except KeyError as e:
        icteki = e
        raise
except KeyError as d:
    print("çıplak raise dışarı aynı nesneyi mi çıkardı:", d is icteki)

try:
    try:
        kaynak()
    except KeyError as e:
        icteki = e
        raise RuntimeError("ölçüm okunamadı") from e
except RuntimeError as d:
    print("from ile çıkan nesne aynı mı:", d is icteki)
    print("from ile nedeni aynı nesne mi:", d.__cause__ is icteki)

print()
DALLAR = ("try", "except", "else", "finally")
print(f"{'durum':<16s}" + "".join(f"{d:<9s}" for d in DALLAR))
for durum, islev in (("hatasız", lambda: 1),
                     ("yakalanan", kaynak),
                     ("yakalanmayan", lambda: 1 // 0)):
    ADIM.clear()
    try:
        try:
            ADIM.append("try")
            islev()
        except KeyError:
            ADIM.append("except")
        else:
            ADIM.append("else")
        finally:
            ADIM.append("finally")
    except ZeroDivisionError:
        pass
    print(f"  {durum:<14s}"
          + "".join(f"{('çalıştı' if d in ADIM else 'atlandı'):<9s}"
                    for d in DALLAR))
```

```
biçim            dışarı çıkan   neden         bağlam        zincir
  çıplak raise   KeyError       -             -             1
  sarmalayan     RuntimeError   -             KeyError      2
  from ile       RuntimeError   KeyError      KeyError      2
  from None ile  RuntimeError   -             KeyError      1
  yutan          -              -             -             0

çıplak raise dışarı aynı nesneyi mi çıkardı: True
from ile çıkan nesne aynı mı: False
from ile nedeni aynı nesne mi: True

durum           try      except   else     finally  
  hatasız       çalıştı  atlandı  çalıştı  çalıştı  
  yakalanan     çalıştı  çalıştı  atlandı  çalıştı  
  yakalanmayan  çalıştı  atlandı  atlandı  çalıştı  
```

## Zincirin Ödettiği

**Çıplak `raise`** dışarı `KeyError` çıkarıyor ve alt satır bunun **aynı nesne** olduğunu
söylüyor. Yeni bir nesne üretilmediği için zincir **1**. Yakalayıp yeniden fırlatmak bilgi
kaybettirmez.

**Sarmalayan** biçim dışarı `RuntimeError` çıkarıyor; `__cause__` boş ama `__context__`
`KeyError`'ı tutuyor. Zincir **2**. Bu bağı kimse yazmadı — istisna başka bir istisna ele
alınırken oluştuğu için yorumlayıcı kendiliğinden kurdu.

**`from` ile** yazılan biçimde `__cause__` doluyor ve zincir yine **2**. Fark çıktının alt
satırlarında: dışarı çıkan nesne iç nesneyle **aynı değil**, ama `__cause__` **aynı
nesneye** işaret ediyor. Sarmalamakla `from` yazmak aynı zincir uzunluğunu verir; ayrıldıkları
yer, bağın **bildirilmiş** mi yoksa kendiliğinden mi kurulduğudur.

**`from None`** zinciri **1**'e indiriyor. `__context__` hâlâ dolu, ama bastırıldığı için
sayıma girmiyor — dışarıdan bakan biri `KeyError`'ı göremez. Alan hatasını gizlemek isteyen
bir sınır için doğru araç, iç ayrıntının kaybolduğunu bilerek kullanılan bir araçtır.

**Yutan** biçim **0** veriyor: dışarı hiçbir şey çıkmıyor. Bir önceki bölümün geniş
yakalamasıyla birleştiğinde bu sıfır tehlikelidir — üç program kusurunun yutulduğu yer tam
olarak burasıdır.

Son tablo dört dalın hangi durumda çalıştığını veriyor. `try` üç durumda da çalışıyor;
`finally` de **üç durumda da** çalışıyor — yakalanmayan istisna dışarı çıkarken bile. `else`
yalnız istisna **oluşmadığında** çalışıyor, `except` yalnız **yakalandığında**. Kaynağı
`try` içinde tutup başarı yolunu `else`'e taşımak, `except` deyiminin yanlışlıkla fazla iş
yakalamasını engeller.

## Özet

- İstisna bir nesnedir, nesnenin bir sınıfı vardır ve `except` bir **sınıf** alır; yakalama
  o sınıfın bütün alt sınıflarını kapsar.
- On bir olay ile yedi yakalama sınıfı **77** çift üretir ve bunların **28**'i tutar; yaprak
  sınıflar **1**–**2** olay tutarken `Exception` **10**, `BaseException` **11** tutar.
- `Exception` yakalaması **6** alan hatasının yanında **3** program kusurunu ve **1**
  protokol olayını da yutar; `BaseException` fazladan **çıkış isteğini** yutar.
- Çıplak `raise` **aynı nesneyi** dışarı çıkarır (zincir **1**); sarmalamak ve `from`
  yazmak zinciri **2** yapar, `from None` onu **1**'e indirir, yutmak **0**'a.
- `finally` üç durumda da çalışır, `else` yalnız istisna oluşmadığında; başarı yolunu `else`
  içine almak `except` deyiminin kapsamını daraltır.

## Sonraki Adım

Bu dersin bütün sınıfları hazır gelenlerdi: `KeyError`, `ValueError`, `OSError`. Ölçüm
onları ortak atalarına göre gruplayabildi, çünkü soyağacı önceden kurulmuştu. Peki fırlatılan
şey **alanın kendi hatasıysa** — ölçüm aygıtının kapsam dışı değer bildirmesi, kayıtta bir
alanın eksik olması gibi? O zaman sınıfı yazan biz oluruz ve onu soyağacının **neresine**
astığımız, sonraki yakalamaların hangisinin tutacağını belirler. Sonraki ders özel istisna
sınıflarının hiyerarşideki yerini ve o yerin yakalama davranışına ödettiğini ölçer.
