[Bölüm 17] Python Dilinde Hatalar ve İstisnalar

Merhaba arkadaşlar, bugün bu yazımda Python programlama dili üzerinde kod yazarken karşılaştığımız hataları ve istisnaları nasıl yöneteceğimizden ve onları nasıl şekillendireceğimizden bahsedeceğim.

Her programalam dilinde yazılan kodlamalarda olduğu gibi Python dilinde de sık sık hatalarla karşılaşacağız. Bu her yazılım geliştiricinin ve her mühendisin vazgeçilmezi de denilebilir.

Python dilinde hatalarımızı try-except bloklarını kullanarak yakalayacağız. Şimdilik basit bir kod ile durumu örnekleyelim.

try:
    sayi = input("Lütfen bir tam sayı giriniz: ")
    sayi = int(sayi)
    print("Tebrikler bir sayı girdiniz")
except:
    print("Girmiş olduğunuz değer bir sayı değildir.")

Çıktı:

Lütfen bir tam sayı giriniz: a
Girmiş olduğunuz değer bir sayı değildir.

Yukarıdaki örnekte de olduğu üzere sayi değişkenini string formatından int formatına dönüştürdük. Bu dönüşüm esnasında hata çıkması durumunda ekrana istediğimiz bir çıktı yazdırdık. Böylelikle hatalarımızı kontrol altına almış olduk. Tabi yukarıdaki örnek giriş seviyesinde bir örnek oldu. İlerleyen örneklerde durumu biraz daha açalım.

Eğer istersek Python’ın vereceği hataya göre kodumuzu kısmen özelleştirebiliriz. Sonuçta except bloğu çıkabilecek her hatada devreye gireceğinden dolayı istemedğimiz durumlarda except bloğunuı devre dışı bırakabiliriz. Pythondaki çıkabilecek kalıp hataların isimlerini except bloğuna dahil ederek sadece yazmış olduğumuz hatalarda bloğumuzu çalıştırabiliriz. Hemen aşağıda durumu örnekledim.

a = 1
while (a <= 2):
    try:
        ilk_sayi = input("Lütfen bir sayı giriniz: ")
        ikinci_sayi = input("Lütfen ikinci sayıyı giriniz: ")
        a = int(ilk_sayi) / int(ikinci_sayi)
    except ValueError:
        print("Sayısal değerler hatalıdır.")
        print("-"*30)
    except ZeroDivisionError:
        print("Hiçbir sayı 0' a bölünemez.")
        print("-"*30)
    a += 1

Çıktı:

Lütfen bir sayı giriniz: 5
Lütfen ikinci sayıyı giriniz: 0
Hiçbir sayı 0' a bölünemez.
------------------------------
Lütfen bir sayı giriniz: 7
Lütfen ikinci sayıyı giriniz: asd
Sayısal değerler hatalıdır.
------------------------------

Eğer istersek bir except bloğuna birden fazla hata çeşidi ekleyerek hatalarımızı gruplandırabiliriz.

a = 1
while (a <= 2):
    try:
        ilk_sayi = input("Lütfen bir sayı giriniz: ")
        ikinci_sayi = input("Lütfen ikinci sayıyı giriniz: ")
        a = int(ilk_sayi) / int(ikinci_sayi)
    except (ValueError,ZeroDivisionError):
        print("Sayısal değerler hatalıdır.")
        print("-"*30)
    a += 1

Çıktı:

Lütfen bir sayı giriniz: 9
Lütfen ikinci sayıyı giriniz: asd
Sayısal değerler hatalıdır.
------------------------------
Lütfen bir sayı giriniz: 3
Lütfen ikinci sayıyı giriniz: 0
Sayısal değerler hatalıdır.
------------------------------

TRY – EXCEPT – FINALLY Blokları

Yukarıda yazdığımız kodlarda dikkat ettiyseniz eğer try bloğunda bir hata çıkarsa otomatik olarak except bloğuna kayıyor ve try bloğunda arta kalan kodları çalıştırmıyor. Hal böyle olunca yazılımcının yazmış olduğu kodlar pasif konuma düşüyor. Bu tarz durumları ortadan kaldırmak için try – except bloklarımıza bir de finally bloğunu ekleyeceğiz. Finally bloğunun özelliği ise içerisinde yazan kodları ister hata çıksın ister hata çıkmasın çalıştırıyor olmasıdır.

try:
    a = int(input("Lütfen bir sayı giriniz: "))
    b = float(input("Lütfen bir ondalıklı sayı giriniz: "))
    cevap = a / b
except ZeroDivisionError:
    print("Sıfıra bölünme hatası mevcuttur.")
    #sadece sıfıra bölünme hatalarında çalışmaktadır
    print("-"*40)
finally:
    print("Şu an finally bloğu çalışmaktadır.")
    #finally bloğu her durumda mutlaka çalışmaktadır.

Çıktı:

Lütfen bir sayı giriniz: 7
Lütfen bir ondalıklı sayı giriniz: 0
Sıfıra bölünme hatası mevcuttur.
----------------------------------------
Şu an finally bloğu çalışmaktadır.

TRY – EXCEPT – ELSE Blokları

Else bloklarından daha önce döngü ve koşullu durumları incelerken bahsetmiştim. Buradaki kullanımının mantığı da klasik else kullanımı ile aynıdır. Kodumuzun hataya girmediği durumlarda barındırdığı kodları çalıştırmaya yarar. Hemen aşağıda bir örnek kod yazdım.

for x in range (9):
    try:
        y = 7 / (x - 5)
    except ZeroDivisionError:
        print("y = 7 / (5 - 5) ---> Sonsuz")
    else:
        print("y = 7 / (5 - {}) ---> {}".format(x,y))

Çıktı:

y = 7 / (5 - 0) ---> -1.4
y = 7 / (5 - 1) ---> -1.75
y = 7 / (5 - 2) ---> -2.3333333333333335
y = 7 / (5 - 3) ---> -3.5
y = 7 / (5 - 4) ---> -7.0
y = 7 / (5 - 5) ---> Sonsuz
y = 7 / (5 - 6) ---> 7.0
y = 7 / (5 - 7) ---> 3.5
y = 7 / (5 - 8) ---> 2.3333333333333335

Hataların Nedenini Bulma

Bir başka yol ise karşılaştığımız hataların nedenini direk olarak ekrana yazdırmaktır. Bu işlemi yaparken dilersek hatanın nedenini bir değişkene atayarak o değişkeni gerekli fonksiyonlarda kullanabiliriz. Hemen aşağıda durumu örnek bir kod ile açıkladım.

try:
    1 / 0
except Exception as e: #e yerine farklı bir değişken de kullanabilirim
    print("Hatanın Sebebi: ",e)

Çıktı:

Hatanın Sebebi:  division by zero

Kasıtlı Olarak Hata Üretmek – Raise Fonksiyonu

Bu sefer hataları kendimiz üreteceğiz. Python’a göre belki hatalı bir durum yoktur ortada ama yazdığımız kodu daha rahat kontrol edebilmek için kendimizce sebepler ekleyerek ve raise fonksiyonunu kullanarak hata üretebiliriz.

def terscevir(s):
    if (type(s) != str):
        raise ValueError("Lütfen string bir değer giriniz.")
    else:
        return s[::-1]
    

print(terscevir("YTÜ - ETK"))
print("-"*30)
print(terscevir(12345))

Çıktı:

KTE - ÜTY
------------------------------
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-8-d6a8e3586d7e> in <module>
      8 print(terscevir("YTÜ - ETK"))
      9 print("-"*30)
---> 10 print(terscevir(12345))

<ipython-input-8-d6a8e3586d7e> in terscevir(s)
      1 def terscevir(s):
      2     if (type(s) != str):
----> 3         raise ValueError("Lütfen string bir değer giriniz.")
      4     else:
      5         return s[::-1]

ValueError: Lütfen string bir değer giriniz.