Exception Handling: try-except-else-finally
Programlar her zaman planladığımız gibi çalışmaz. Kullanıcı sayı yerine harf girer, dosya bulunamaz, internet bağlantısı kopar. İşte bu beklenmedik durumlarla nasıl başa çıkacağımızı öğreneceğiz.
Bu derste Python'ın hata yönetim sistemi olan exception mekanizmasını derinlemesine inceleyeceğiz. Hazırsan başlayalım!
Exception Nedir?
Exception, programın çalışması sırasında ortaya çıkan beklenmedik bir durumdur. Python bir hatayla karşılaştığında normal akışı durdurur ve bir exception (istisna) fırlatır.
🔥 Yangın Alarmı Analojisi
Exception'ları bir binadaki yangın alarm sistemi gibi düşün. Normal şartlarda bina sorunsuz çalışır — insanlar işlerini yapar, asansörler hareket eder, ışıklar yanar. Ama bir yangın çıktığında ne olur?
Alarm çalar → Python bir exception fırlatır
İnsanlar durur → Program normal akışını durdurur
Tahliye planı devreye girer → Exception handler çalışır
İtfaiye gelir → Hata uygun şekilde ele alınır
Eğer alarm sistemi yoksa (exception handling yoksa), yangın kontrolsüz yayılır ve bina çöker (program crash olur). Ama iyi bir alarm sistemiyle yangını erken tespit eder, insanları tahliye eder ve hasarı minimize edersin.
İşte exception handling tam olarak budur — programını "yangına karşı" koruma altına almak.
Hatayı Görmek
Bir exception oluştuğunda Python bize oldukça detaylı bir hata mesajı verir:
# Bu kodu çalıştırınca ne olur?
sayi = int("merhaba")Çıktı şöyle olur:
Traceback (most recent call last):
File "main.py", line 1, in <module>
sayi = int("merhaba")
ValueError: invalid literal for int() with base 10: 'merhaba'Bu hata mesajı aslında çok değerli bilgiler içerir:
Traceback: Hatanın nerede oluştuğunu gösterir (dosya adı, satır numarası)
ValueError: Hatanın türünü belirtir
Mesaj: Ne olduğunu açıklar
Exception handling olmadan program bu noktada tamamen durur. Altındaki hiçbir kod çalışmaz. Bu da kullanıcı için kötü bir deneyim demek.
try-except: Temel Kullanım
Python'da hataları yakalamak için try-except bloğunu kullanırız. Mantık basit: "Şunu dene, hata olursa şunu yap."
try:
sayi = int(input("Bir sayı girin: "))
print(f"Girdiğiniz sayı: {sayi}")
except ValueError:
print("Hata! Lütfen geçerli bir sayı girin.")
print("Program devam ediyor...")Bu kodda ne oluyor?
trybloğundaki kod çalıştırılırKullanıcı "abc" girerse
int()birValueErrorfırlatırPython
except ValueErrorbloğuna atlarHata mesajı yazdırılır
Program çökmeden devam eder
try-except olmadan aynı hata programı tamamen durdururdu. Ama şimdi zarif bir şekilde hatayı ele aldık.
Basit Bir Hesap Makinesi
Biraz daha gerçekçi bir örnek yapalım:
def bolenle_bol(a, b):
try:
sonuc = a / b
print(f"{a} / {b} = {sonuc}")
except ZeroDivisionError:
print("Hata: Sıfıra bölme yapılamaz!")
bolenle_bol(10, 3) # 10 / 3 = 3.3333...
bolenle_bol(10, 0) # Hata: Sıfıra bölme yapılamaz!
bolenle_bol(42, 7) # 42 / 7 = 6.0ZeroDivisionError sadece sıfıra bölme durumunda tetiklenir. Başka bir hata türü oluşursa bu except bloğu onu yakalamaz — ve bu aslında iyi bir şey. Neden mi? Çünkü her hatayı aynı şekilde ele almak istemezsin.
Birden Fazla except Bloğu
Bir try bloğunda farklı türde hatalar oluşabilir. Her biri için ayrı bir except bloğu yazabilirsin:
def guvenli_eris(liste, index):
try:
deger = liste[index]
sonuc = 10 / deger
return sonuc
except IndexError:
print(f"Hata: {index} indeksi liste dışında!")
except ZeroDivisionError:
print("Hata: Listede sıfır değeri var, bölme yapılamaz!")
except TypeError:
print("Hata: Listede sayısal olmayan değer var!")
sayilar = [5, 0, "abc", 2]
guvenli_eris(sayilar, 0) # 2.0 döner
guvenli_eris(sayilar, 1) # Sıfıra bölme hatası
guvenli_eris(sayilar, 2) # TypeError
guvenli_eris(sayilar, 10) # IndexErrorPython except bloklarını yukarıdan aşağıya kontrol eder. İlk eşleşen except bloğu çalışır ve diğerleri atlanır. Bu yüzden sıralama önemli olabilir.
Birden Fazla Exception'ı Tek Blokta Yakalama
Bazen farklı hata türleri için aynı işlemi yapmak istersin. Bu durumda tuple kullanabilirsin:
def sayi_cevir(deger):
try:
return float(deger)
except (ValueError, TypeError):
print(f"'{deger}' sayıya çevrilemedi!")
return None
print(sayi_cevir("3.14")) # 3.14
print(sayi_cevir("hello")) # Hata mesajı, None
print(sayi_cevir(None)) # Hata mesajı, None(ValueError, TypeError) parantezlerine dikkat et — bu bir tuple. İkisinden biri oluşursa aynı except bloğu çalışır.
else Bloğu: Hata Olmazsa Çalışır
try-except yapısına bir de else ekleyebilirsin. else bloğu sadece hiçbir exception oluşmadığında çalışır.
"Ama try bloğunun sonuna da yazabilirdim?" diyebilirsin. Teknik olarak evet, ama else kullanmanın önemli bir avantajı var: else bloğundaki hatalar except tarafından yakalanmaz. Bu sayede hangi kodun korunduğunu ve hangisinin korunmadığını net bir şekilde ayırırsın.
def dosya_oku(dosya_adi):
try:
dosya = open(dosya_adi, "r")
except FileNotFoundError:
print(f"'{dosya_adi}' bulunamadı!")
else:
# Dosya başarıyla açıldıysa burası çalışır
icerik = dosya.read()
print(f"Dosya içeriği ({len(icerik)} karakter):")
print(icerik[:100]) # İlk 100 karakter
dosya.close()
dosya_oku("mevcut_dosya.txt") # Dosyayı okur
dosya_oku("olmayan_dosya.txt") # Hata mesajı verirtry-except-else Akış Şeması
try bloğu çalışır
├── Hata OLURSA → except bloğu çalışır
└── Hata OLMAZSA → else bloğu çalışırelse bloğu şu durumlarda çok işe yarar:
Başarılı durumda ek işlem yapmak istediğinde
trybloğunu mümkün olduğunca kısa tutmak istediğindeHangi kodun "korumalı" olduğunu açıkça belirtmek istediğinde
finally Bloğu: Her Durumda Çalışır
finally bloğu ne olursa olsun çalışır — hata olsun ya da olmasın, return ifadesi olsa bile.
Bu genellikle temizlik işlemleri için kullanılır: dosya kapatma, veritabanı bağlantısını kesme, kilit bırakma gibi.
def veritabani_sorgusu(sorgu):
baglanti = None
try:
baglanti = veritabani_baglan() # Bağlantı kur
sonuc = baglanti.calistir(sorgu)
return sonuc
except BaglantiHatasi:
print("Veritabanına bağlanılamadı!")
except SorguHatasi:
print("SQL sorgusu hatalı!")
finally:
# Bağlantı açıldıysa MUTLAKA kapat
if baglanti:
baglanti.kapat()
print("Bağlantı kapatıldı.")finally bloğunun gücünü daha basit bir örnekle görelim:
def bolme_yap(a, b):
try:
sonuc = a / b
return sonuc
except ZeroDivisionError:
print("Sıfıra bölünemez!")
return None
finally:
print("İşlem tamamlandı.") # HER ZAMAN çalışır
print(bolme_yap(10, 2))
# Çıktı:
# İşlem tamamlandı.
# 5.0
print(bolme_yap(10, 0))
# Çıktı:
# Sıfıra bölünemez!
# İşlem tamamlandı.
# NoneDikkat et: return ifadesinden önce finally çalışıyor! Python try bloğundan çıkmadan önce finally'yi mutlaka çalıştırır.
Komple Yapı: try-except-else-finally
def guvenli_bolme(a, b):
try:
sonuc = a / b
except ZeroDivisionError:
print("Hata: Sıfıra bölünemez!")
sonuc = None
except TypeError:
print("Hata: Sayısal değer gerekli!")
sonuc = None
else:
print(f"Başarılı: {a} / {b} = {sonuc}")
finally:
print("--- İşlem bitti ---")
return sonucAkış şeması:
try → Hata var mı?
├── EVET → except çalışır → finally çalışır
└── HAYIR → else çalışır → finally çalışır💡 İpucu:
finallygeneldewithstatement ile birlikte kullanılmaz çünküwithzaten otomatik temizlik yapar.finally'yiwithkullanamadığın durumlarda tercih et.
Exception Hiyerarşisi
Python'daki tüm exception'lar bir sınıf hiyerarşisi oluşturur. Bu hiyerarşiyi anlamak, doğru exception'ı yakalamanın anahtarıdır.
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── ArithmeticError
│ ├── ZeroDivisionError
│ ├── OverflowError
│ └── FloatingPointError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── ValueError
├── TypeError
├── OSError
│ ├── FileNotFoundError
│ ├── PermissionError
│ └── FileExistsError
├── AttributeError
├── NameError
├── RuntimeError
│ └── RecursionError
└── StopIterationBu Hiyerarşi Neden Önemli?
Bir except bloğu belirttiğin exception'ı ve onun tüm alt sınıflarını yakalar:
try:
sozluk = {"ad": "Python"}
print(sozluk["yas"])
except LookupError:
# Hem KeyError hem IndexError'u yakalar!
print("Arama hatası!")LookupError, KeyError'ın üst sınıfıdır. Bu yüzden except LookupError yazınca KeyError da yakalanır.
Bu durumun tehlikeli bir versiyonu:
# ÇOK GENİŞ — bunu yapma!
try:
# ... bir sürü kod ...
pass
except BaseException:
# KeyboardInterrupt bile yakalanır!
# Ctrl+C ile programı durduramaz olursun!
print("Bir şey oldu")BaseException yakalamak KeyboardInterrupt'ı da yakalar, yani kullanıcı Ctrl+C ile programı durduramaz. Bu çok kötü bir pratik.
Yaygın Exception Türleri
Python'da en sık karşılaşacağın exception türlerini tanıyalım:
ValueError — Yanlış Değer
Doğru tür ama yanlış değer verildiğinde:
# Sayıya çevrilemeyen string
int("merhaba") # ValueError
int("12.5") # ValueError (int için geçersiz)
# Geçersiz değer
import math
math.sqrt(-1) # ValueErrorTypeError — Yanlış Tür
Yanlış veri türü kullanıldığında:
# String ile sayı toplama
"5" + 3 # TypeError
# Çağrılamayan nesneyi çağırma
x = 42
x() # TypeError: 'int' object is not callable
# Yanlış argüman sayısı
len(1, 2, 3) # TypeErrorKeyError — Sözlükte Olmayan Anahtar
ogrenci = {"ad": "Ali", "yas": 20}
print(ogrenci["not"]) # KeyError: 'not'IndexError — Liste Dışı İndeks
meyveler = ["elma", "armut", "muz"]
print(meyveler[5]) # IndexError: list index out of rangeFileNotFoundError — Dosya Bulunamadı
with open("olmayan_dosya.txt") as f:
pass # FileNotFoundErrorAttributeError — Olmayan Özellik/Metot
sayi = 42
sayi.upper() # AttributeError: 'int' has no attribute 'upper'NameError — Tanımsız Değişken
print(tanimlanmamis_degisken) # NameErrorZeroDivisionError — Sıfıra Bölme
sonuc = 10 / 0 # ZeroDivisionErrorBu hataları bilmek, doğru except bloğunu yazmak için çok önemli. Her hatanın bir nedeni var ve o nedene göre farklı aksiyonlar alman gerekir.
Bare except Neden Kötü?
"Her hatayı yakalayayım" düşüncesiyle şöyle kod yazan çok var:
# KÖTÜ PRATİK — bunu yapma!
try:
sonuc = hesapla(veri)
except:
print("Bir hata oluştu")Bu "bare except" (çıplak except) diye adlandırılır ve ciddi sorunlara yol açar:
KeyboardInterrupt yakalanır — Ctrl+C çalışmaz
SystemExit yakalanır —
sys.exit()çalışmazHangi hata olduğunu bilemezsin — debug etmek imkansızlaşır
Gerçek bugları gizler — Programda bir hata var ama göremiyorsun
# YANLIŞ — Bare except
try:
veri = dosyadan_oku()
islenmiş = isle(veri)
kaydet(islenmiş)
except:
print("Bir hata oluştu") # Hangi hata? Nerede? Neden?Bunun yerine ne yapmalı?
# DOĞRU — Spesifik exception'lar
try:
veri = dosyadan_oku()
islenmiş = isle(veri)
kaydet(islenmiş)
except FileNotFoundError:
print("Dosya bulunamadı!")
except ValueError as e:
print(f"Veri işleme hatası: {e}")
except IOError as e:
print(f"Kaydetme hatası: {e}")Eğer gerçekten "tüm exception'ları" yakalamak istiyorsan (ki nadiren gerekir), en azından Exception kullan:
# KABUL EDİLEBİLİR — Exception kullanımı
try:
riskli_islem()
except Exception as e:
print(f"Beklenmeyen hata: {e}")
# Hatayı logla, sonra gerekirse tekrar fırlat
raiseexcept Exception en azından KeyboardInterrupt ve SystemExit gibi sistem exception'larını yakalamaz. Bu çok önemli bir fark.
⚠️ Dikkat: Bare except (
except:) yerine her zamanexcept Exception:kullan. Daha da iyisi, spesifik exception türlerini yakala. Bu debugging sürecini çok kolaylaştırır ve beklenmedik hataları gizlemeni engeller.
raise ile Hata Fırlatma
Sadece hata yakalamak yetmez — bazen kendi hatalarını fırlatman da gerekir. raise keyword'ü tam olarak bunu yapar.
Basit raise Kullanımı
def yas_kontrol(yas):
if yas < 0:
raise ValueError("Yaş negatif olamaz!")
if yas > 150:
raise ValueError("Geçersiz yaş değeri!")
return f"Yaşınız: {yas}"
try:
print(yas_kontrol(25)) # Yaşınız: 25
print(yas_kontrol(-5)) # ValueError fırlatılır
except ValueError as e:
print(f"Hata: {e}")raise ile istediğin exception türünü fırlatabilirsin. Fonksiyonun girdilerini doğrulamak için çok kullanılır.
raise ile Hatayı Tekrar Fırlatma
Bazen bir hatayı yakalayıp bir şeyler yaptıktan sonra tekrar fırlatmak istersin:
import logging
def veritabani_kaydet(veri):
try:
# Veritabanına kaydetmeyi dene
_kaydet(veri)
except Exception as e:
# Hatayı logla
logging.error(f"Kaydetme hatası: {e}")
# Hatayı tekrar fırlat — çağıran fonksiyon da bilsin
raise
# Kullanım
try:
veritabani_kaydet({"ad": "Ali"})
except Exception:
print("Kaydetme başarısız, yedek sisteme geçiliyor...")Tek başına raise (argümansız) yazınca, o an yakalanan exception aynen tekrar fırlatılır. Bu, hatayı loglayıp sonra üst katmana iletmek için mükemmel bir pattern.
Koşullu raise
def indirimli_fiyat(fiyat, indirim_orani):
if not isinstance(fiyat, (int, float)):
raise TypeError(f"Fiyat sayısal olmalı, {type(fiyat).__name__} verildi")
if not 0 <= indirim_orani <= 100:
raise ValueError(f"İndirim oranı 0-100 arası olmalı, {indirim_orani} verildi")
return fiyat * (1 - indirim_orani / 100)
try:
print(indirimli_fiyat(100, 20)) # 80.0
print(indirimli_fiyat(100, 150)) # ValueError
except (TypeError, ValueError) as e:
print(f"Geçersiz girdi: {e}")raise kullanırken mesaj vermek iyi bir pratik. Bu mesaj as e ile yakalandığında str(e) olarak okunabilir.
as Keyword: Hata Nesnesine Erişim
Exception yakaladığında genellikle hata hakkında bilgi almak istersin. as keyword'ü exception nesnesini bir değişkene atar:
try:
sozluk = {"Python": 1991, "Java": 1995}
print(sozluk["JavaScript"])
except KeyError as e:
print(f"Anahtar bulunamadı: {e}")
print(f"Hata türü: {type(e).__name__}")
print(f"Hata argümanları: {e.args}")Çıktı:
Anahtar bulunamadı: 'JavaScript'
Hata türü: KeyError
Hata argümanları: ('JavaScript',)Exception Nesnesinin Özellikleri
Her exception nesnesi bazı yararlı özelliklere sahiptir:
try:
with open("/root/gizli_dosya.txt") as f:
pass
except PermissionError as e:
print(f"Mesaj: {e}")
print(f"Args: {e.args}")
print(f"Tür: {type(e).__name__}")
print(f"Errno: {e.errno}") # OS hata kodu
print(f"Strerror: {e.strerror}") # OS hata mesajı
print(f"Filename: {e.filename}") # Dosya adıOSError ve alt sınıfları (FileNotFoundError, PermissionError vb.) ekstra özellikler taşır: errno, strerror, filename.
Birden Fazla except ile as Kullanımı
def veri_isle(deger):
try:
sayi = int(deger)
sonuc = 100 / sayi
return sonuc
except ValueError as e:
print(f"Değer hatası: {e}")
return None
except ZeroDivisionError as e:
print(f"Bölme hatası: {e}")
return None
except TypeError as e:
print(f"Tür hatası: {e}")
return None
print(veri_isle("abc")) # Değer hatası: invalid literal...
print(veri_isle("0")) # Bölme hatası: division by zero
print(veri_isle(None)) # Tür hatası: int() argument...Her except bloğu kendi as değişkenine sahip. Bu değişken sadece o except bloğu içinde geçerli — blok dışında erişilemez (Python 3'te bu değişken blok sonunda silinir).
Pratik: Güvenli Input Alma
Şimdi öğrendiklerimizi birleştirelim. Kullanıcıdan güvenli bir şekilde sayı alalım:
def sayi_al(mesaj, min_deger=None, max_deger=None, max_deneme=3):
"""Kullanıcıdan güvenli sayı girişi alır."""
for deneme in range(max_deneme):
try:
deger = float(input(mesaj))
if min_deger is not None and deger < min_deger:
raise ValueError(f"Değer en az {min_deger} olmalı")
if max_deger is not None and deger > max_deger:
raise ValueError(f"Değer en fazla {max_deger} olmalı")
return deger
except ValueError as e:
kalan = max_deneme - deneme - 1
if kalan > 0:
print(f"Geçersiz: {e}. {kalan} hakkınız kaldı.")
else:
print("Çok fazla hatalı deneme!")
return None
# Kullanım
yas = sayi_al("Yaşınızı girin: ", min_deger=0, max_deger=150)
if yas is not None:
print(f"Yaşınız: {yas}")
else:
print("Yaş alınamadı.")Bu fonksiyon şunları yapıyor:
Geçersiz girdi yakalanır (
ValueError)Aralık kontrolü yapılır (çok küçük/büyük)
Deneme sayısı sınırlanır
Her durumda anlamlı geri bildirim verilir
Hesap Makinesi Örneği
def hesap_makinesi():
"""Basit ama güvenli hesap makinesi."""
islemler = {
"+": lambda a, b: a + b,
"-": lambda a, b: a - b,
"*": lambda a, b: a * b,
"/": lambda a, b: a / b,
}
print("Basit Hesap Makinesi")
print("Çıkmak için 'q' yazın.\n")
while True:
try:
girdi = input("İşlem (ör: 10 + 5): ").strip()
if girdi.lower() == "q":
print("Güle güle!")
break
parcalar = girdi.split()
if len(parcalar) != 3:
raise ValueError("Format: sayı işlem sayı")
a = float(parcalar[0])
islem = parcalar[1]
b = float(parcalar[2])
if islem not in islemler:
raise ValueError(f"Geçersiz işlem: {islem}")
sonuc = islemler[islem](a, b)
print(f"Sonuç: {sonuc}\n")
except ValueError as e:
print(f"Hata: {e}\n")
except ZeroDivisionError:
print("Hata: Sıfıra bölünemez!\n")
except KeyboardInterrupt:
print("\nProgram sonlandırıldı.")
break
hesap_makinesi()Bu örnekte dikkat edilecek noktalar:
Her hata türü için farklı mesaj
KeyboardInterruptayrıca ele alınıyor (Ctrl+C)while Truedöngüsü — hata olsa bile program devam ediyorraise ValueError(...)ile kendi doğrulama hatalarımızı fırlatıyoruz
İç İçe try-except
Bazen try-except bloklarını iç içe kullanman gerekebilir:
def dosya_isle(dosya_adi):
try:
with open(dosya_adi, "r") as f:
for satir_no, satir in enumerate(f, 1):
try:
sayi = float(satir.strip())
print(f"Satır {satir_no}: {sayi * 2}")
except ValueError:
print(f"Satır {satir_no}: '{satir.strip()}' sayı değil, atlanıyor")
except FileNotFoundError:
print(f"Dosya bulunamadı: {dosya_adi}")
except PermissionError:
print(f"Dosya okuma izni yok: {dosya_adi}")Dıştaki try-except dosya açma hatalarını yakalar. İçteki try-except her satırı ayrı ayrı işler — bir satırda hata olması diğer satırların işlenmesini engellemez.
Bu pattern özellikle dosya işleme ve veri dönüştürme senaryolarında çok işe yarar. Her kaydı bağımsız olarak ele almak, bir kayıttaki hatanın tüm işlemi çökertmesini engeller.
Exception Handling'de Performans
Merak edebilirsin: "try-except kullanmak programımı yavaşlatır mı?"
Kısa cevap: Hata olmadığında neredeyse hiç yavaşlatmaz. Python, try bloğuna girmek için çok az ek maliyet öder. Asıl maliyet bir exception fırlatıldığında ortaya çıkar.
import time
# try-except ile (hata yok)
baslangic = time.time()
for _ in range(1_000_000):
try:
x = 1 + 1
except:
pass
sure_try = time.time() - baslangic
# try-except olmadan
baslangic = time.time()
for _ in range(1_000_000):
x = 1 + 1
sure_normal = time.time() - baslangic
print(f"try-except ile: {sure_try:.4f}s")
print(f"Normal: {sure_normal:.4f}s")
# Fark yok denecek kadar az!Ama exception fırlatılması pahalıdır. Bu yüzden exception'ları normal program akışı için kullanma. Exception'lar adı üstünde istisnai durumlar içindir.
# KÖTÜ — Exception'ı kontrol akışı olarak kullanma
for i in range(100):
try:
deger = sozluk[i]
except KeyError:
pass
# İYİ — Önce kontrol et
for i in range(100):
if i in sozluk:
deger = sozluk[i]💡 İpucu: Bu kural her zaman geçerli değildir. Python topluluğunda "EAFP" (Easier to Ask Forgiveness than Permission) prensibi yaygındır — yani "izin sormak yerine affetmek kolaydır." Bunu bir sonraki derste detaylıca işleyeceğiz.
Yaygın Hatalar ve Anti-Pattern'ler
1. Çok Geniş try Bloğu
# KÖTÜ — Çok fazla kod try içinde
try:
dosya = open("veri.txt")
icerik = dosya.read()
veri = json.loads(icerik)
sonuc = isle(veri)
kaydet(sonuc)
bildirim_gonder(sonuc)
except Exception:
print("Bir şeyler yanlış gitti") # Ama ne?
# İYİ — Sadece riskli kodu try içine al
try:
dosya = open("veri.txt")
icerik = dosya.read()
except FileNotFoundError:
print("Dosya bulunamadı")
else:
try:
veri = json.loads(icerik)
except json.JSONDecodeError:
print("Geçersiz JSON formatı")
else:
sonuc = isle(veri)
kaydet(sonuc)2. Hatayı Sessizce Yutma
# KÖTÜ — Hatayı yut, hiçbir şey yapma
try:
riskli_islem()
except Exception:
pass # 🙈 Hata? Hangi hata?
# İYİ — En azından logla
try:
riskli_islem()
except Exception as e:
logging.warning(f"İşlem başarısız: {e}")
# veya: raise (tekrar fırlat)3. Exception'ı Yanlış Yerde Yakalama
# KÖTÜ — Her fonksiyon kendi hatasını yutuyor
def adim1():
try:
return riskli_is()
except Exception:
return None # Hata bilgisi kayboldu
def adim2(veri):
try:
return isle(veri)
except Exception:
return None # Yine kayboldu
# İYİ — Hataların yukarı çıkmasına izin ver
def adim1():
return riskli_is() # Hata olursa fırlasın
def adim2(veri):
return isle(veri) # Hata olursa fırlasın
# Ana fonksiyonda yakala
try:
v = adim1()
sonuc = adim2(v)
except RiskliIsHatasi:
print("Adım 1 başarısız")
except IslemeHatasi:
print("Adım 2 başarısız")⚠️ Dikkat: Exception'ları mümkün olduğunca yukarıda (çağıran kodda) yakala. Her fonksiyonun kendi hatasını yutması, debugging'i kabusa çevirir. Hataların akmasına izin ver, en uygun yerde yakala.
Özet
Bu derste Python'ın exception handling mekanizmasını derinlemesine inceledik. İşte önemli noktalar:
Exception programın çalışma anında oluşan hatalardır; "yangın alarmı" gibi düşün — erken tespit et, doğru müdahale et.
try-except temel hata yakalama yapısıdır.
trybloğuna riskli kodu,exceptbloğuna hata durumunda yapılacak işlemi yaz.else bloğu hata olmadığında, finally bloğu her durumda çalışır.
finallyözellikle kaynak temizliği (dosya kapatma, bağlantı kesme) için kullanılır.Spesifik exception yakala —
except:(bare except) yerineexcept ValueError:gibi spesifik türler kullan. Bu hem debugging'i kolaylaştırır hemKeyboardInterruptgibi sistem exception'larını yanlışlıkla yakalamayı engeller.raise ile kendi hatalarını fırlatabilirsin. Input doğrulama ve iş kuralı ihlallerinde çok kullanılır.
raise(argümansız) yakalanan hatayı tekrar fırlatır.as keyword'ü ile exception nesnesine erişerek hata mesajı, türü ve ek bilgileri okuyabilirsin. Bu bilgiler loglama ve kullanıcı geri bildirimi için çok değerli.
AI Asistan
Sorularını yanıtlamaya hazır