5. İstisnalar
Şimdi istisnalara geçelim.

5.1. [exceptions_01] komut dosyası
İlk komut dosyası, istisnaları yönetmenin gerekliliğini göstermektedir.
Ne olacağını görmek için kasıtlı olarak bir hata oluşturuyoruz (exceptions-01.py):
-
satır bize şunu gösterir:
-
istisnanın türü: ZeroDivisionError;
- ilgili hata mesajı: sıfıra bölme. Mesaj İngilizce. Bu, değiştirmek isteyebileceğimiz bir şeydir.
Temel bir kural, Python yorumlayıcısı tarafından üretilen istisnaları önlemek için her şeyi yapmamız gerektiğidir. Hataları kendimiz yönetmeliyiz.
İstisna işleme sözdizimi şöyledir:
try:
actions susceptibles de lancer une exception
except (Ex1, Ex2…) as ex:
actions de gestion de l'exception [ex]
except (Ex11, Ex12…) as ex:
actions de gestion de l'exception [ex]
finally:
actions toujours exécutées qu'il y ait exception ou non
try bloğunda, bir istisna (hata) oluştuğu anda işlemlerin yürütülmesi durur. Bu durumda, yürütme, except cümlelerinden birindeki işlemlerle devam eder:
-
- satır: Oluşan [ex] istisnası, (Ex1, Ex2…) tuple'ına ait bir türdeyse veya bunlardan birinden türetilmişse, 4. satırdaki işlemler yürütülür;
-
- satır: istisna 3. satır tarafından yakalanmamışsa ve başka bir [except] cümlesi varsa, aynı süreç tekrarlanır. Vb…;
- [try]'te ortaya çıkabilecek farklı istisna türlerini yönetmek için gerekli olduğu kadar çok sayıda [except] maddesi olabilir;
- istisna hiçbir [except] maddesinde işlenmemişse, çağrı yapan koda iletilir. Çağrı yapan kodun kendisi bir try / except yapısı içindeyse, istisna yeniden işlenir; aksi takdirde çağrılan yöntemler zinciri boyunca yukarı doğru iletilmeye devam eder. Son çare olarak, istisna Python yorumlayıcısına ulaşır. Yorumlayıcı, bu durumda yürütülen programı durdurur ve önceki örnekte gösterilen türde bir hata mesajı görüntüler. Dolayısıyla kural şudur: ana program, çağrılan yöntemlerden yukarı doğru iletilebilecek tüm istisnaları durdurmalıdır;
-
- satır: [finally] ifadesi, istisna oluşmuş olsun (except bloğunun devamı) ya da oluşmasın (try bloğunun devamı), her durumda yürütülür. Bu durum, bir istisna oluşmuş ve yakalanmamış olsa bile geçerlidir. Bu durumda, istisna çağıran koda ulaşmadan önce [finally] cümlesi yürütülecektir;
Bir istisna, meydana gelen hatayla ilgili bilgileri de beraberinde taşır. Bu bilgilere aşağıdaki sözdizimiyle ulaşılabilir:
except MyException as exception:
[exception], meydana gelen istisnadır. [exception.args] ise istisnanın parametre tuple'ını temsil eder.
Bir istisna oluşturmak için şu sözdizimi kullanılır:
raise MyException(param1, param2…)
kullanılır; burada MyException genellikle BaseException sınıfından türetilmiş bir sınıftır. Sınıfın oluşturucusuna aktarılan parametreler, [ex]'in [except] cümlesi tarafından yakalanan istisna olması durumunda, istisna yakalama yapılarının except cümlesinde [ex.args] sözdizimi ile kullanılabilir olacaktır.
Bu kavramlar aşağıdaki komut dosyasında gösterilmiştir.
5.2. [exceptions_02] betiği
Aşağıdaki komut dosyası hataları açıkça yönetir:
# istisna yönetimi
essai = 0
# bir hata oluşturulur ve yönetilir
x = 2
try:
x = 4 / 0
except ZeroDivisionError as erreur:
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur}")
# x'in değeri değişmedi
print(f"x={x}")
# yeniden başlıyoruz
essai += 1
try:
x = 4 / 0
except BaseException as erreur:
# en genel istisna yakalanıyor
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur}")
# farklı türde istisnalar yakalanabilir
# yürütme, istisnayı işleyebilen ilk [except]'te durur
essai += 1
try:
x = 4 / 0
except ValueError as erreur:
# bu istisna burada meydana gelmez
print(f"essai n° {essai} : {erreur}")
except BaseException as erreur:
# en genel istisna yakalanır
print(f"essai n° {essai} : (Exception) {erreur}")
except ZeroDivisionError as erreur:
# belirli bir tür yakalanıyor
print(f"essai n° {essai} : (ZeroDivisionError) {erreur}")
# sırayı değiştirerek yeniden başlıyoruz
essai += 1
try:
x = 4 / 0
except ValueError as erreur:
# bu istisna burada gerçekleşmiyor
print(f"essai n° {essai} : {erreur}")
except ZeroDivisionError as erreur:
# belirli bir tür yakalanıyor
print(f"essai n° {essai} : (ZeroDivisionError) {erreur}")
except BaseException as erreur:
# en genel istisna yakalanıyor
print(f"essai n° {essai} : (Exception) {erreur}")
# argüman içermeyen bir except ifadesi
essai += 1
try:
x = 4 / 0
except:
# istisnanın niteliği önemli değildir
print(f"essai n° {essai} : il y a eu un problème")
# başka bir istisna türü
essai += 1
try:
# x tamsayıya dönüştürülemez
x = int("x")
except ValueError as erreur:
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur}")
# bir istisna, programa erişilebilir bir tuple içinde bilgi taşır
essai += 1
try:
x = int("x")
except ValueError as erreur:
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur}, paramètres={erreur.args}")
# istisnalar atılabilir
essai += 1
try:
raise ValueError("param1", "param2", "param3")
except ValueError as erreur:
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur}, paramètres={erreur.args}")
# kendi istisnalarınızı oluşturabilirsiniz
# bunlar [BaseException] sınıfından türetilmelidir
class MyError(BaseException):
pass
# MyError istisnası tetiklenir
essai += 1
try:
raise MyError("info1", "info2", "info3")
except MyError as erreur:
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur}, paramètres={erreur.args}")
# MyError istisnası bir hata mesajıyla atılır
essai += 1
try:
raise MyError("mon msg d'erreur")
except MyError as erreur:
# hata, yakalanan istisnadır
print(f"essai n° {essai} : {erreur.args[0]}")
# finally bloğu her zaman yürütülür
# istisna olsun ya da olmasın
essai += 1
x = None
try:
x = 1
except:
# istisna
print(f"essai n° {essai} : exception")
finally:
# her durumda yürütülür
print(f"essai n° {essai} : finally x={x}")
essai += 1
x = None
try:
x = 2 / 0
except:
# istisna
print(f"essai n° {essai} : exception")
finally:
# her durumda yürütülür
print(f"essai n° {essai} : finally x={x}")
# bir koşul eklemek zorunlu değildir [except]
essai += 1
try:
# hata verilir
x = 4 / 0
finally:
# her durumda yürütülür
print(f"essai n° {essai} : finally x={x}")
Notlar:
- 4-12. satırlar: sıfıra bölme hatası işlenir;
-
- satır: Oluşan istisnayı yakalayıp ekrana yazdırır;
-
- satır: Meydana gelen istisna nedeniyle, x, 7. satırda bir değer almadı ve dolayısıyla değeri değişmedi;
- satır 14-21: Aynı işlemi tekrarlıyoruz, ancak bu sefer BaseException türünde daha üst düzey bir istisnayı yakalıyoruz. ZeroDivisionError istisnası, BaseException sınıfından türediği için, except cümlesi bunu durduracaktır;
- 23-36. satırlar: Çeşitli istisna türlerini yönetmek için birden fazla except cümlesi eklenir. İstisna hiçbir except cümlesini karşılamıyorsa, tek bir except cümlesi yürütülecek ya da hiçbiri yürütülmeyecektir;
- satır 38-50: [except] maddelerinin sırasını değiştirerek aynı işlemi tekrarlarız; böylece bu maddenin rolünü gösteririz;
- satır 52-58: except cümlesi hiçbir argüman içermeyebilir. Bu durumda, tüm istisnaları durdurur;
- satır 60-67: ValueError istisnasını ekler;
- satır 69-75: istisna tarafından taşınan bilgiler alınır;
- satır 77-83: bir istisnayı tetikleme (raise) yöntemi tanıtılır;
- satır 86-106: özel bir istisna sınıfı olan MyError'in kullanımını gösterir. MyError sınıfı, yalnızca temel sınıf olan BaseException'ten türetilmiştir. Temel sınıfa hiçbir şey eklemez. Ancak artık except cümlelerinde açıkça adlandırılabilir;
- 108-130. satırlar: finally cümlesinin kullanımını gösterir;
- 132-139. satırlar: Bu satırlar, [except] cümlesinin zorunlu olmadığını göstermektedir;
Ekran çıktısı şu şekildedir:
5.3. [exceptions_03] komut dosyası
Bu yeni komut dosyası, istisnaların çağrı zincirinde yukarı doğru iletilmesini göstermektedir:
# özel bir istisna
class MyError(BaseException):
pass
# üç işlev
def f1(x: int) -> int:
# istisnalar yönetilmez - otomatik olarak üst katmana iletilir
return f2(x)
def f2(y: int) -> int:
# istisnalar yönetilmiyor - otomatik olarak üst katmana iletiliyor
return f3(y)
def f3(z: int) -> int:
if (z % 2) == 0:
# z çift ise, bir istisna atılır
raise MyError("exception dans f3")
else:
return 2 * z
# ---------- main
# istisnalar, çağrılan yöntemler zinciri boyunca yukarı doğru iletilir
# bir yöntem tarafından yakalanana kadar. Burada bu yöntem main olacaktır
try:
print(f1(4))
except MyError as erreur:
print(f"type : {type(erreur)}, arguments : {erreur.args}")
# istisnaları zenginleştiren üç başka işlev daha vardır
def f4(x: int) -> int:
try:
return f5(x)
except MyError as erreur:
# istisna zenginleştirilir ve ardından yeniden atılır
raise MyError("exception dans f4", erreur)
def f5(y: int) -> int:
try:
return f6(y)
except MyError as erreur:
# istisnayı zenginleştirip yeniden atıyoruz
raise MyError("exception dans f5", erreur)
def f6(z: int) -> int:
if (z % 2) == 0:
# z çift ise bir istisna atıyoruz
raise MyError("exception dans f6")
else:
return 2 * z
# ---------- ana işlev
try:
print(f4(4))
except MyError as erreur:
# istisna görüntülenir
print(f"type : {type(erreur)}, arguments : {erreur.args}")
# istisna yığınını geriye doğru izleyebiliriz
err = erreur
# hata mesajı görüntülenir
print(err.args[0])
# Bir istisna kapsüllenmiş mi?
while len(err.args) == 2 and isinstance(err.args[1], BaseException):
# istisna değişikliği
err = err.args[1]
# 1. argüman hata mesajıdır
print(err.args[0])
Notlar:
- 25-32. satırlarda, main --> f1 --> f2 --> f3 (30. satır) çağrısında, f3 tarafından tetiklenen MyError istisnası, main'e kadar iletilecektir. Bu istisna, 31. satırdaki except maddesi tarafından işlenecektir;
- 61-75. satırlar: main --> f4 --> f5 --> f6 çağrısında (62. satır), f6 tarafından tetiklenen MyError istisnası, main'e kadar geriye doğru izlenecektir. Ardından, 63. satırdaki except maddesi tarafından işlenecektir. Bu sefer, çağıran işlevler zincirinde yukarı doğru ilerlerken, yukarı doğru ilerleyen MyError istisnası, kendisi de başka bir istisna içinde kapsüllenmiştir;
- 66-75. satırlar: istisna yığınından nasıl yukarı çıkılacağını gösterir;
-
- satır: [isinstance(instance, Classe)] işlevi, [instance] nesnesinin [Classe] türünde veya bunun türevlerinden biri olması durumunda True değerini döndürür. Burada, en üst düzeydeki [BaseException] istisnasını kullandık; bu sayede tüm istisnaları yakalayabiliyoruz;
Ekran çıktısı şu şekildedir: