Python'da hata yönetimi try ve except ile yapılır: hata çıkarabilecek kodu try bloğuna yazarsınız, bir istisna (exception) oluşursa Python o bloğun geri kalanını atlar ve türü eşleşen except bloğunu çalıştırır. İsteğe bağlı else bloğu yalnızca hiç istisna çıkmadığında, finally bloğu ise her durumda çalışır. İstisnayı yakalarsanız program çökmez, try deyiminden sonraki satırdan devam eder.
Bu yazıda dört bloğun ne zaman ve hangi sırayla çalıştığını, birden fazla except yazarken sıranın neden önemli olduğunu, Python 3.14 ile gelen parantezsiz except A, B: yazımını, finally içinde return kullanınca çıkan yeni uyarıyı ve sık yapılan hataları Python 3.15.2 ile çalıştırılmış örneklerle anlatıyoruz. Kendi istisnanızı fırlatmak ve tanımlamak ayrı bir konudur; onu raise ve özel istisna yazısında ele alıyoruz. Python'a yeni başlıyorsanız konu sırası için Python öğrenme rehberi sayfasına bakabilirsiniz.
Sözdizimi hatası ile istisna arasındaki fark
Python belgeleri hataları iki gruba ayırır. Birincisi sözdizimi hatasıdır (SyntaxError): kod daha çalışmadan, ayrıştırma aşamasında yakalanır. Örneğin bir if satırının sonunda iki nokta unutulursa dosyanın hiçbir satırı çalışmaz. Bu tür hataları try ile yakalayamazsınız, çünkü try deyiminin kendisi de henüz çalışmamıştır; kodu düzeltmeniz gerekir.
İkinci grup istisnalardır: sözdizimi doğru olan bir ifade çalışırken bir sorunla karşılaşır. Sıfıra bölme, olmayan bir sözlük anahtarını okuma ya da sayıya çevrilemeyen bir metni int() ile dönüştürme bu türdendir. İstisnalar kendiliğinden ölümcül değildir; yakalamazsanız program durur ve bir traceback (hata izi) basılır. Traceback'in son satırı istisnanın türünü ve ayrıntısını gösterir, üst satırlar ise hatanın hangi dosyada ve hangi satırda oluştuğunu sırasıyla listeler:
fiyatlar = {"elma": 30}
print(fiyatlar["armut"])
# hata: KeyError: 'armut'Traceback (most recent call last):
File "ornek.py", line 2, in <module>
print(fiyatlar["armut"])
~~~~~~~~^^^^^^^^^
KeyError: 'armut'Yukarıdaki çıktı Python 3.15.2'nin gerçek çıktısıdır; yalnızca uzun geçici dosya yolunu ornek.py olarak kısalttık. ~ ve ^ işaretleri satırın tam olarak hangi parçasının hataya yol açtığını gösterir. Sık karşılaşılan hata mesajlarının ne anlama geldiğini Python sık hata mesajları yazısında tek tek açıklıyoruz.
try ve except ile ilk örnek
En basit kullanımda try bloğuna riskli kodu, except satırına da yakalamak istediğiniz istisna sınıfını yazarsınız. as ile verdiğiniz isim, yakalanan istisna nesnesine bağlanır; bu nesneyi print() ile yazdırdığınızda hatanın açıklaması görünür:
metin = "12a"
try:
sayi = int(metin)
print("Bu satır çalışmaz")
except ValueError as hata:
print("Geçersiz giriş:", hata)
print("Program devam ediyor")
# çıktı: Geçersiz giriş: invalid literal for int() with base 10: '12a'
# çıktı: Program devam ediyorAkış şöyle işler: önce try bloğu çalışır. int(metin) bir ValueError fırlattığı anda bloğun kalanı (buradaki ikinci print) atlanır. Python sonra except satırlarına sırayla bakar; istisnanın türü yazılan sınıfla ya da onun bir alt sınıfıyla eşleşirse o blok çalışır. Blok bittikten sonra program try deyiminin tamamından sonraki satıra geçer. Hiçbir except eşleşmezse istisna bir dıştaki try deyimine, oradan da çağıran fonksiyona doğru yükselir; hiçbir yerde yakalanmazsa program traceback ile sonlanır.
Bir try bloğu yalnızca kendi içinde yazılan satırları değil, o satırların çağırdığı fonksiyonların içinde oluşan istisnaları da yakalar. Bu sayede hatayı, onu anlamlı biçimde ele alabileceğiniz katmanda yakalayabilirsiniz:
def ortalama(sayilar):
return sum(sayilar) / len(sayilar)
def rapor(sayilar):
try:
print("Ortalama:", ortalama(sayilar))
except ZeroDivisionError:
print("Liste boş, ortalama hesaplanamadı")
rapor([4, 6, 8])
rapor([])
# çıktı: Ortalama: 6.0
# çıktı: Liste boş, ortalama hesaplanamadıBirden fazla except ve sıranın önemi

Farklı hata türlerine farklı tepki vermek için aynı try deyimine birden fazla except yazabilirsiniz. Belgelere göre en fazla bir except bloğu çalışır ve ilk eşleşen kazanır. Ayrıca bir except bloğunun içinde çıkan yeni bir istisna, aynı deyimin diğer except blokları tarafından yakalanmaz:
def bol(a, b):
try:
return a / b
except ZeroDivisionError:
return "sıfıra bölünemez"
except TypeError as e:
return f"tip hatası: {e}"
print(bol(10, 4))
print(bol(1, 0))
print(bol("10", 2))
# çıktı: 2.5
# çıktı: sıfıra bölünemez
# çıktı: tip hatası: unsupported operand type(s) for /: 'str' and 'int'Eşleşme sınıf hiyerarşisine göre yapılır: except LookupError yazarsanız LookupError'dan türeyen KeyError ve IndexError da yakalanır. Tersi geçerli değildir; except KeyError bir IndexError'ı yakalamaz. Bu yüzden genel sınıfı özel sınıftan önce yazarsanız özel blok hiçbir zaman çalışmaz:
veri = {"ad": "Ayşe"}
try:
veri["yas"]
except LookupError:
print("LookupError bloğu yakaladı")
except KeyError:
print("Bu satıra hiç gelinmez")
# çıktı: LookupError bloğu yakaladıKural basittir: except bloklarını en özelden en genele doğru sıralayın. Dosya işlemlerinde bu, önce FileNotFoundError veya PermissionError, en sonda da onların ortak atası OSError yazmak demektir. Sık karşılaşılan hiyerarşi şöyledir:
| Genel sınıf | Kapsadığı bazı alt sınıflar | Tipik durum |
|---|---|---|
| ArithmeticError | ZeroDivisionError, OverflowError | Matematik işlemi hataları |
| LookupError | KeyError, IndexError | Olmayan anahtar ya da sıra numarası |
| OSError | FileNotFoundError, PermissionError, FileExistsError, TimeoutError | Dosya, ağ ve işletim sistemi hataları |
| ValueError | UnicodeDecodeError, UnicodeEncodeError | Türü doğru ama değeri uygunsuz veri |
| NameError | UnboundLocalError | Tanımsız ya da henüz atanmamış isim |
| Exception | Yukarıdakilerin hepsi | Sistemden çıkış dışındaki neredeyse tüm hatalar |
Tek except ile birden fazla tür: Python 3.14 yazımı
Birkaç türe aynı tepkiyi vermek istiyorsanız türleri tek bir except satırında toplayabilirsiniz. Klasik yazım türleri parantez içinde bir demet (tuple) olarak vermektir: except (ValueError, TypeError):. Python 3.14 ile gelen PEP 758 sayesinde, as kullanmadığınız sürece parantezleri yazmak zorunlu değildir:
def donustur(deger):
try:
return int(deger)
except ValueError, TypeError:
return None
print(donustur("42"), donustur("kırk"), donustur(None))
# çıktı: 42 None NoneBurada "kırk" metni ValueError, None ise TypeError üretir; ikisi de aynı bloğa düşer. İstisna nesnesine bir isim vermek istediğinizde parantez hâlâ zorunludur. except ValueError, TypeError as e: yazarsanız Python 3.15.2 kodu hiç çalıştırmadan şu sözdizimi hatasını verir:
kod = """
try:
pass
except ValueError, TypeError as e:
pass
"""
try:
compile(kod, "ornek.py", "exec")
except SyntaxError as e:
print(e.msg)
# çıktı: multiple exception types must be parenthesized when using 'as'Doğru yazım except (ValueError, TypeError) as e: biçimindedir. Parantezsiz yazım yalnızca 3.14 ve sonrasında geçerlidir; kodunuz daha eski sürümlerde de çalışacaksa parantezli biçimi kullanmaya devam edin. Sürüm farklarının toplu listesi için Python 3.15 yenilikleri yazısına bakabilirsiniz.
else bloğu: yalnızca hata çıkmazsa çalışan kod

else bloğu tüm except bloklarından sonra yazılır ve try bloğu hiçbir istisna üretmeden, return, break veya continue ile ayrılmadan bittiğinde çalışır. Asıl faydası, korumak istediğiniz kodu küçük tutmanızdır. Belgeler de bunu önerir: başarı durumunda çalışacak satırları try içine eklemek yerine else'e koymak, beklemediğiniz bir istisnayı yanlışlıkla yakalamanızı önler. Ayrıca else içinde çıkan bir istisna, aynı deyimdeki except blokları tarafından yakalanmaz:
def kare_yaz(metin):
try:
sayi = int(metin)
except ValueError:
print(f"{metin!r} sayı değil")
else:
print(f"{metin!r} geçerli, karesi {sayi ** 2}")
kare_yaz("7")
kare_yaz("yedi")
# çıktı: '7' geçerli, karesi 49
# çıktı: 'yedi' sayı değilfinally bloğu: her durumda çalışan temizlik kodu
finally bloğu, try deyimi tamamlanmadan önce yapılan son iştir ve istisna çıksa da çıkmasa da çalışır. İstisna hiçbir except tarafından yakalanmadıysa Python onu geçici olarak saklar, finally bloğunu çalıştırır ve sonra istisnayı yeniden fırlatır. Aynı durum except veya else bloğunun içinde çıkan istisnalar için de geçerlidir. Aşağıdaki örnekte üç senaryoyu birlikte görüyorsunuz:
def islem(x, y):
try:
sonuc = x / y
except ZeroDivisionError:
print("sıfıra bölme!")
else:
print("sonuç:", sonuc)
finally:
print("finally çalıştı")
islem(6, 3)
islem(6, 0)
try:
islem("6", "3")
except TypeError as e:
print("dışarıda yakalandı:", e)
# çıktı: sonuç: 2.0
# çıktı: finally çalıştı
# çıktı: sıfıra bölme!
# çıktı: finally çalıştı
# çıktı: finally çalıştı
# çıktı: dışarıda yakalandı: unsupported operand type(s) for /: 'str' and 'str'Üçüncü çağrıda iki metni bölmek TypeError üretir. Bu tür için bir except olmadığından önce finally çalışır, ardından istisna fonksiyonun dışına çıkar ve dıştaki try tarafından yakalanır. try bloğu return, break veya continue ile ayrılırken de finally o adımdan hemen önce çalışır:
def ayarlari_oku():
try:
print("try içinde")
return "ayarlar"
finally:
print("finally, return'den hemen önce")
print(ayarlari_oku())
# çıktı: try içinde
# çıktı: finally, return'den hemen önce
# çıktı: ayarlarGerçek uygulamalarda finally dosya, ağ bağlantısı ya da kilit gibi dış kaynakları serbest bırakmak için kullanılır. Ancak dosyalar ve kilitler gibi nesneler zaten with deyimini destekler; çoğu durumda try ile finally yazmak yerine with ve context manager kullanmak daha kısa ve daha güvenlidir.
finally içinde return: Python 3.14 uyarısı
finally bloğu return, break veya continue çalıştırırsa saklanan istisna sessizce yok olur. try içindeki return değeri de ezilir, çünkü bir fonksiyonun dönüş değeri en son çalışan return ile belirlenir. Bu davranış kafa karıştırıcı olduğu için Python 3.14 ile gelen PEP 765 derleyicinin bu durumda SyntaxWarning vermesini sağladı. Aşağıdaki dosyayı çalıştırdığınızda uyarı, kod daha derlenirken standart hata akışına yazılır:
def durum():
try:
return True
finally:
return False
print(durum())
# çıktı: Falseornek.py:5: SyntaxWarning: 'return' in a 'finally' block
return False
FalseFonksiyon True yerine False döndürür. Daha tehlikeli olanı, try içinde oluşan bir istisnanın da aynı şekilde kaybolmasıdır: try: 1/0 ve finally: return 42 yazılmış bir fonksiyon hata vermeden 42 döndürür. Çözüm, dönüş değerini finally dışında belirlemek ve finally bloğunu yalnızca temizlik için kullanmaktır.
İstisna nesnesi: as ile gelen değişken ve sys.exception()
except ... as isim ile bağlanan değişken, blok bitince Python tarafından silinir. Dil referansı bunun nedenini şöyle açıklar: traceback'i taşıyan istisna nesnesi, bulunduğu çerçeveyle bir referans döngüsü kurar ve bu döngü tüm yerel değişkenleri gereğinden uzun süre bellekte tutar. İstisnayı bloktan sonra kullanmak istiyorsanız onu başka bir isme atayın:
try:
1 / 0
except ZeroDivisionError as hata:
saklanan = hata
print(type(saklanan).__name__)
print("hata" in dir())
# çıktı: ZeroDivisionError
# çıktı: FalseYerleşik istisnaların args özelliği yapıcıya verilen argümanları bir demet olarak saklar; str() ise bu argümanları okunur biçimde döndürür. except bloğunun içindeyken o an işlenen istisnaya sys.exception() ile de ulaşabilirsiniz; bloktan çıkınca bu değer önceki hâline (çoğunlukla None) döner:
import sys
try:
int("on")
except ValueError as e:
print(e.args)
print(repr(sys.exception()))
print(sys.exception())
# çıktı: ("invalid literal for int() with base 10: 'on'",)
# çıktı: ValueError("invalid literal for int() with base 10: 'on'")
# çıktı: NoneException, BaseException ve çıplak except
Tüm istisnaların ortak atası BaseException'dır. Onun alt sınıfı Exception, programı sonlandırmaya yönelik olmayan tüm yerleşik hataların atasıdır. sys.exit() çağrısının fırlattığı SystemExit ve kullanıcının Ctrl+C ile ürettiği KeyboardInterrupt ise bilerek Exception'ın dışında tutulmuştur; böylece except Exception yazan bir kod programın kapanmasını yanlışlıkla engellemez:
import sys
try:
sys.exit(3)
except Exception:
print("Exception bunu yakalamaz")
except SystemExit as e:
print("SystemExit yakalandı, çıkış kodu:", e.code)
# çıktı: SystemExit yakalandı, çıkış kodu: 3Hiç tür yazmadığınız bir except: satırı (çıplak except) her şeyi, SystemExit ve KeyboardInterrupt dahil, yakalar. Dil kuralına göre böyle bir blok varsa en sonda olmalıdır. Belgelerin önerisi, yakalayacağınız türleri olabildiğince özel seçmek ve beklemediğiniz istisnaların yukarı çıkmasına izin vermektir. Exception'ı yakalamanız gereken bir yer varsa (örneğin bir sunucunun en dış döngüsü), en yaygın desen hatayı kaydedip çıplak raise ile yeniden fırlatmaktır. Hata kaydı için logging modülü yazısına bakabilirsiniz.
EAFP ve LBYL: önce sor mu, sonra özür dile mi?
Python sözlüğü (glossary) iki kodlama tarzını tanımlar. LBYL ("look before you leap", atlamadan önce bak) tarzında işlemden önce koşulları if ile kontrol edersiniz. EAFP ("easier to ask for forgiveness than permission", izin istemekten özür dilemek kolaydır) tarzında ise işlemin başarılı olacağını varsayar, olmazsa istisnayı yakalarsınız. Sözlük, EAFP'nin Python'da yaygın olduğunu belirtir ve çok iş parçacıklı ortamlarda LBYL'nin kontrol ile işlem arasında bir yarış durumuna (race condition) açık olduğunu not eder: siz if ile kontrol ettikten sonra başka bir iş parçacığı veriyi değiştirebilir.
stok = {"kalem": 12}
# LBYL
if "silgi" in stok:
adet = stok["silgi"]
else:
adet = 0
# EAFP
try:
adet2 = stok["silgi"]
except KeyError:
adet2 = 0
print(adet, adet2, stok.get("silgi", 0))
# çıktı: 0 0 0Son satırdaki dict.get() örneği de bir hatırlatmadır: bazı durumlar için dilin zaten istisnasız bir yolu vardır. Sözlükte varsayılan değer için get(), dosya silerken yokluğu önemsiz saymak için Path.unlink(missing_ok=True) gibi seçenekler try bloğundan daha okunurdur.
Uygulama: geçerli giriş gelene kadar tekrar sormak
Resmî öğreticideki klasik örnek, kullanıcı geçerli bir tam sayı girene kadar soruyu tekrarlayan bir döngüdür. Aşağıda input() yerine bir liste kullandık ki örnek kendi başına çalışabilsin; gerçek programda girdiler yerine input("Yaşınız: ") yazmanız yeterlidir. continue hatalı girişte döngünün başına döner, else ise yalnızca dönüşüm başarılı olduğunda çalışır:
girdiler = ["on iki", "", "-5", "12"]
for metin in girdiler:
try:
yas = int(metin)
if yas < 0:
raise ValueError("yaş negatif olamaz")
except ValueError as e:
print(f"{metin!r} geçersiz ({e})")
continue
else:
print("Kaydedilen yaş:", yas)
break
# çıktı: 'on iki' geçersiz (invalid literal for int() with base 10: 'on iki')
# çıktı: '' geçersiz (invalid literal for int() with base 10: '')
# çıktı: '-5' geçersiz (yaş negatif olamaz)
# çıktı: Kaydedilen yaş: 12Negatif sayı kontrolünde kendimiz bir ValueError fırlattık; böylece iki farklı geçersizlik nedeni aynı except bloğunda toplandı. raise deyiminin ayrıntıları, kendi istisna sınıfınızı yazmak ve hataları zincirlemek için Python raise rehberine geçebilirsiniz. Gerçek bir terminal programında kullanıcı Ctrl+C'ye basarsa KeyboardInterrupt oluşur; bu örnekte onu yakalamadığımız için program beklendiği gibi sonlanır.
Sık yapılan hatalar

- Çok geniş try bloğu: Fonksiyonun tamamını tek bir
tryiçine almak, hangi satırın hatayı ürettiğini gizler ve beklemediğiniz istisnaları da yakalar. Yalnızca hata çıkabilecek satırı koruyun, devamınıelse'e taşıyın. - Hatayı sessizce yutmak:
except Exception: passprogramın yanlış veriyle devam etmesine yol açar. En azından hatayı kaydedin ya da yeniden fırlatın. - Genel sınıfı önce yazmak:
except Exceptionveyaexcept OSErrorözel türlerin üstündeyse alttaki bloklar ölü koda dönüşür. - Çıplak except kullanmak:
except:Ctrl+C'yi vesys.exit()'i de yakalar; programı kapatmak zorlaşır. - as ile parantezi unutmak: Python 3.14 ve sonrasında
except A, B:geçerlidir amaexcept A, B as e:sözdizimi hatasıdır; parantez kullanın. - finally içinde return: İstisnaları ve asıl dönüş değerini yok eder; 3.14 itibarıyla
SyntaxWarningverir. - except değişkenini bloktan sonra kullanmak:
as eile bağlanan isim blok sonunda silinir; sonradan erişirsenizNameErroralırsınız. - SyntaxError'u try ile yakalamaya çalışmak: Aynı dosyadaki sözdizimi hatası kod çalışmadan önce bulunur;
tryancakcompile(),eval()veya içe aktarma gibi çalışma anında derlenen kodlardaki sözdizimi hatalarını yakalayabilir.
Sık Sorulan Sorular
Python'da tüm hataları nasıl yakalarım?
except Exception as e: sistemden çıkış dışındaki neredeyse tüm hataları yakalar. Bunu yalnızca programın en dış katmanında, hatayı kaydedip yeniden fırlatmak ya da kullanıcıya anlaşılır bir mesaj göstermek için kullanın. Çıplak except: ve except BaseException Ctrl+C ile çıkışı da engellediği için önerilmez.
else ile finally arasındaki fark nedir?
else yalnızca try bloğu hatasız bittiğinde çalışır ve içindeki istisnalar aynı deyimin except blokları tarafından yakalanmaz. finally ise hata olsun olmasın, hatta return ile çıkılırken bile her durumda çalışır.
Birden fazla istisna türünü tek satırda nasıl yakalarım?
Türleri parantez içinde verin: except (ValueError, TypeError) as e:. Python 3.14 ve sonrasında as kullanmıyorsanız except ValueError, TypeError: da yazabilirsiniz.
Hatayı yakalayıp yine de programın durmasını nasıl sağlarım?
except bloğunda gereken işi yaptıktan sonra argümansız raise yazın. Bu, aynı istisnayı traceback'iyle birlikte yeniden fırlatır. Ayrıntılar raise ve özel istisna yazısında.
try kullanmak programı yavaşlatır mı?
Belgeler bu konuda bir ölçüm vermez. Pratik ölçüt okunabilirliktir: koşul kontrolü kodu karmaşıklaştırıyorsa ya da yarış durumuna açıksa EAFP tarzı try, basit bir varsayılan değer yetiyorsa dict.get() gibi hazır araçlar daha uygundur.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Python öğrenme rehberi · Python raise ve özel istisna · Python with ve context manager · Python sık hata mesajları · Python dosya okuma ve yazma · Python logging modülü · Python 3.15 yenilikleri