8. Hata Ayıklama#

Python’da hatalı bir işlem yaptığımız, örneğin tanımlanmamış bir değişkeni kullanmaya çalıştığımızda, bir fonksiyona hatalı veri tipinde argüman girdiğimizde, hatanın nerden kaynaklandığını belirten mesajlarla karşılaşırız. Örneğin daha önce tanımlanmamış olan bir x değişkenini kullanmaya çalıştığımızda aşağıdaki gibi bir mesajla karşılaşırız.

print(x)
----------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-81745ac23551> in <module>()
----> 1 print(x)

NameError: name 'x' is not defined

Hata mesajındaki son satır, hatanın neden kaynaklandığını belirtmektedir. Buradaki mesaj, (NameError: İsim Hatası) ‘x’ değişkeninin tanımlanmamış olduğunu söylüyor. Aynı şekilde herhangi bir pakette yer alan fonksiyonu, paketi ya da ilgili fonksiyonu içeri aktarmaksızın kullanmaya kalkarsak da aynı mesajla karşılaşırız.

reduce(lambda x1,x2: x1 + x2, [3, 5, 7, 9])
NameError: name 'reduce' is not defined

Ya da program çalışırken sir sayıyı sıfırla bölmeye çalışırsak buna ilişkin bir hata mesajıyla karşılaşırız ve programın çalışması durur. ZeroDivisionError, sıfırla bölme hatası anlamına geliyor.

5 / 0
ZeroDivisionError: division by zero

Şimdi de sayısal bir değer kullanmamız gereken yerde metin tipinde bir değişken kullanalım. Görüldüğü gibi sayısal değer kullanmamız gereken bir fonksiyonda str (metin) tipinde veri kullandığımız için TypeError (Tür Hatası) ile karşılaşıyoruz.

us = 'iki'
5 ** us
TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'str'

Son bir örnek olarak bilinmeyen bir paketi içeri aktarmaya çalışalım. Burada da ModuleNotFound yani modül bulunamadı hatası ile karşılaşıyoruz.

import yeni_paket
ModuleNotFoundError: No module named 'yeni_paket'

Yukarıda örneklerini gördüğümüz, NameError, ZeroDivisionError, ModuleNotFoundError gibi mesajlara istisna (exeption) denir. Python’da yer karşılaşılabilecek hatalar için geliştirilmiş çok sayıda istisna mesajı vardır. Bunların https://docs.python.org/3/library/exceptions.html adresinden ulaşılabilir.

Biz de yazdığımız programlarda kullanıcı hatalarına karşı uygun istisna mesajları yazarak olası hataların önüne geçebiliriz. Python’da hata yakalamanın bir yolu try except anahtar kelimelerini kullanmaktır. Try kelimesinden sonra, çalıştırılmak istenen kod, except kelimesinden sonra da bu kod çalışmazsa verilecek mesaj yer alır. Örnek olarak verilen değerin karekökünü bulan bir fonksiyon yazalım.

def karekok(girdi):
    try:
        return girdi ** 0.5
    except:
        print('Argüman sayısal bir değer olmalı!!!')
print(karekok(16))
4.0
print(karekok('dort'))
Argüman sayısal bir değer olmalı!!!
None

Tanımladığımız fonksiyon önce verilen değerin karekökünü bulmayı deniyor (2. ve 3. satırlar). Burada bir hata ile karşılaşırsa except anahtar kelimesi ile gösterilen kısma geçiyor ve belirtilen hata mesajını veriyor.

Örnek olarak basit bir başka fonksiyona bakalım. Şimdi de bir bölme fonksiyonu yazalım. Tabii ki böyle bir fonksiyona hiçbir zaman ihtiyacımız olmayacak ama try, except yapısının nasıl çalıştığını görmek için bu fonksiyonu kullanabiliriz.

def bolme(x,y):
    try:
        return x / y
    except:
        print("Sıfırla bölme hatası")
print(bolme(10, 4))
2.5
print(bolme(5, 0))
Sıfırla bölme hatası
None

Beklediğimiz gibi bölen sıfır olduğunda program istediğimiz hatayı veriyor ve None değerini döndürüyor.

Son olarak metin girilmesi gerektiği halde girilmeyen bir fonksiyon için try except yapısı kuralım.

def tekrar_et(kelime, sayi):
     try:
        print("Sonuc: " + kelime * sayi)
     except:
         print("Argüman olarak bir metin ve bir tamsayı girin!!!")
print(tekrar_et("deneme ", 3))
Sonuc: deneme deneme deneme 
None
print(tekrar_et(5, 3))
Argüman olarak bir metin ve bir tamsayı girin!!!
None

İstersek türünü bildiğimiz hatalardan biri veya daha fazlası ile karşılaşıldığında da belirli bir hata mesajı verilmesini sağlayabiliriz. Yukarıdaki karekök alma örneğinde sayısal bir değer yerine metin tipindeki verinin girilmesinin TypeError olduğunu biliyoruz. Bu nedenle programa TypeError ile karşılaştığında nasıl bir mesaj vermesi gerektiğini söyleyebiliriz.

def karekok(girdi):
    try:
        return girdi ** 0.5
    except TypeError:
        print('Argüman sayısal bir değer olmalı!!!')
print(karekok("yirmi"))
Argüman sayısal bir değer olmalı!!!
None

Yazdığımız kodun belirli durumlarda hata ya da uyarı mesajı vermesini de isteyebiliriz. Yukarıda verdiğimiz karekök bulma örneğinde eğer eksi bir sayı girilirse normalde program karmaşık bir sayı üretecektir.

print(karekok(-16))
(2.4492935982947064e-16+4j)

Ancak, eksi bir sayı girildiğinde uyarı mesajı verilmesini istiyor olalım.

def karekok(girdi):
    if girdi < 0:
        raise ValueError("Eksi bir sayı girdiniz!!!")
    try:
        return girdi ** 0.5
    except TypeError:
        print('Argüman sayısal bir değer olmalı!!!')
print(karekok(-16))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[15], line 1
----> 1 print(karekok(-16))

Cell In[14], line 3, in karekok(girdi)
      1 def karekok(girdi):
      2     if girdi < 0:
----> 3         raise ValueError("Eksi bir sayı girdiniz!!!")
      4     try:
      5         return girdi ** 0.5

ValueError: Eksi bir sayı girdiniz!!!

def tekrar_et(kelime, sayi):
     if sayi < 0:
         raise ValueError("Sayı sıfırdan küçük olamaz!!!")
     try:
        print("Sonuc: " + kelime * sayi)
     except:
         print("Argüman olarak bir metin ve bir tamsayı girin!!!")
print(tekrar_et("deneme", -3))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[19], line 1
----> 1 print(tekrar_et("deneme", -3))

Cell In[18], line 3, in tekrar_et(kelime, sayi)
      1 def tekrar_et(kelime, sayi):
      2      if sayi < 0:
----> 3          raise ValueError("Sayı sıfırdan küçük olamaz!!!")
      4      try:
      5         print("Sonuc: " + kelime * sayi)

ValueError: Sayı sıfırdan küçük olamaz!!!