İstisnalar, modüller ve sistematik hata ayıklama

Söz dizimi doğru olan bir program her durumda sorunsuz çalışmayabilir. Dosya bulunamayabilir, metin sayıya çevrilemeyebilir, beklenen anahtar sözlükte olmayabilir ya da bir hesapta sayı sıfıra bölünebilir.

Bu hafta istisna (exception) kavramını öğreneceğiz. Program çalışırken çıkan belirli sorunları try/except ile yakalamayı, gerektiğinde raise ile kendiniz istisna yükseltmeyi ve Python’la birlikte gelen modülleri kullanmayı göreceğiz. Hata ararken de rastgele değil, adım adım ilerlemeyi öğreneceğiz.

Bu bölümün kapsamı

NoteSınavda sorulur
  • Söz dizimi, çalışma zamanı ve mantık hatasının ayrımı
  • try / except ile belirli istisnayı ele alma ve geniş except riski
  • FileNotFoundError, KeyError ve ValueError eşlemesi
  • raise ile sözleşme ihlalini bildirme ve assertten ayırma
  • None sinyali ve is None denetimi
  • Traceback’te hata türü, mesaj ve kendi kodundaki satır
  • import ile modül kullanımı ve main guard’ın ayırdığı iki durum
  • Kendi istisna sınıfını tanımlama
  • logging modülü
  • Adım adım çalıştıran hata ayıklayıcı arayüzü

Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.

Program hata vermiyor ama sonuç yanlış; bu ne tür bir hatadır?

Hataların hepsi kırmızı bir mesajla gelmez. Önce hataları türlerine ayıracağız. Sonra beklediğimiz hataları program çökmeden yakalamayı ve bir hata iz dökümünü (traceback) okumayı öğreneceğiz. Traceback, Python’ın hata anında yazdığı ve hatanın hangi satırlardan geçerek oluştuğunu gösteren dökümdür.

Hata türlerini ayırmak

Söz dizimi hatası

if puan >= 60
    print("Geçti")

if satırının sonundaki iki nokta eksik. Python kodu çalıştırmaya başlamadan SyntaxError verir.

Çalışma zamanı hatası

sayi = int("abc")       # ValueError
# 10 / 0               # ZeroDivisionError
# [1, 2][5]            # IndexError

Kodun yazımı kurallara uygun; sorun ancak satır çalıştığında ortaya çıkar.

Mantık hatası

Program çalışır ama yanlış sonuç verir. Örneğin daire çevresinin formülünü eksik yazalım:

def daire_cevresi(yaricap):
    return 3.14 * yaricap   # Hatalı: 2 çarpanı eksik

Doğru formülde π sayısı için math.pi değerini kullanabiliriz. math, Python’la birlikte gelen standart kütüphanenin modüllerinden biridir:

import math

def daire_cevresi(yaricap):
    return 2 * math.pi * yaricap
assert abs(daire_cevresi(1) - 2 * math.pi) < 0.000001

Bu tür hatayı Python kendiliğinden yakalayamayabilir. Sonucu beklenen değerle karşılaştırmak size düşer; yukarıdaki assert satırı da bunu yapar.

Important

Hata ayıklarken “program çalışıyor mu?” sorusu yetmez. Hatayı nasıl düzelteceğinizi hatanın türü ve programın ne yapması gerektiği belirler.

Söz dizimi, çalışma zamanı ve mantık hatalarının karşılaştırılması.

Programlama hatalarının türleri

İstisna nedir?

Python bir satırı çalıştırırken devam edemeyeceği bir durumla karşılaşırsa bir istisna oluşturur. İstisna yakalanmazsa program o noktada durur:

int("on")

ValueError oluşur. Türün adı ve yanındaki mesaj sorunun ne olduğunu söyler: "on" metni tam sayıya çevrilemiyor.

try / except

metin = "42"

try:
    sayi = int(metin)
    print("Sayı:", sayi)
except ValueError:
    print("Geçerli bir tam sayı değil")

metin = "abc" olsaydı dönüşüm başarısız olur, print("Sayı:", sayi) satırı atlanır ve yalnızca except ValueError bloğu çalışırdı.

Hata nesnesinin mesajını okumak: as e

Bazen Python’ın verdiği asıl mesajı da görmek isteriz: kullanıcıya göstermek ya da hatayı ararken okumak için.

metin = "abc"

try:
    sayi = int(metin)
except ValueError as e:
    print("Hata türü: ValueError")
    print("Ayrıntı:", e)

e, oluşan istisna nesnesine bu blok içinde verdiğimiz addır. Bu örnekte print("Ayrıntı:", e) satırı invalid literal for int() with base 10: 'abc' mesajını yazdırır.

Note

Python’ın mesajını kullanıcıya olduğu gibi göstermek zorunda değilsiniz. Kod yazarken ve hata ararken ise except ... as e sorunun ayrıntısını görmenizi sağlar.

Tahmin et: hangi blok çalışır?

Çalıştırmadan önce çıktıyı tahmin edin. Sonra girdi_metni değerini "yetmis" yapıp yeniden tahmin edin.

Alıştırma: dönüşüm hatasını ele alın

Kodu try/except ValueError kullanacak biçimde değiştirin; geçersiz metinde Geçerli sayı değil yazdırılsın.

girdi_metni = "abc"

try:
    sayi = int(girdi_metni)
    print(sayi)
except ValueError:
    print("Geçerli sayı değil")

Belirli hata türünü yakalamak

Türü yazılmamış bir except bloğu, beklemediğiniz birçok hatayı da sessizce yutabilir:

try:
    ...
except:
    ...

Yalnızca sayı dönüşümünde çıkan hatayı bekliyorsanız türünü yazın:

try:
    sayi = int(metin)
except ValueError:
    ...

Böylesi daha açıklayıcıdır: kodu okuyan kişi hangi hatanın beklendiğini görür.

Warning

“Program hiç hata vermesin” diye her şeyi türsüz, geniş bir except ile kapatmak hata ayıklamayı zorlaştırır. Yalnızca beklediğiniz ve karşılığında ne yapacağınızı bildiğiniz hata türlerini yakalayın.

Birden fazla hata türü

def bol(metin, bolen):
    sayi = int(metin)
    return sayi / bolen

try:
    sonuc = bol("20", 0)
    print(sonuc)
except ValueError:
    print("Metin sayıya dönüştürülemedi")
except ZeroDivisionError:
    print("Sıfıra bölme yapılamaz")

Her türü ayrı bir except bloğunda yakaladığınızda hatanın nedenini ayırt edebilirsiniz. Bu örnekte ZeroDivisionError bloğu çalışır.

12. haftanın dosya hataları

Geçen hafta dosyanın bulunamayabileceğini, bir sütunun eksik olabileceğini ya da bir değerin sayıya çevrilemeyebileceğini söylemiştik. Şimdi bu durumları istisnalarla yakalayalım.

FileNotFoundError

try:
    with open("veri.csv", "r", encoding="utf-8") as dosya:
        icerik = dosya.read()
except FileNotFoundError as e:
    print("Dosya bulunamadı: veri.csv")
    print("Ayrıntı:", e)

except bloğu yalnızca dosya bulunamadığında çalışır. Dosyanın içindeki veri hataları bu bloğa karışmaz.

KeyError: beklenen sütun/alan yok

DictReader’ın verdiği kayıtta "puan" sütunu yoksa kayit["puan"] erişimi KeyError verir:

kayit = {"ad": "Deniz"}

try:
    puan = int(kayit["puan"])
except KeyError as e:
    print("Beklenen alan bulunamadı:", e)

Bir CSV dosyasını okurken üç hata bir arada şöyle yakalanır:

import csv

try:
    with open("ogrenciler.csv", "r", encoding="utf-8-sig", newline="") as dosya:
        okuyucu = csv.DictReader(dosya, delimiter=";")

        for kayit in okuyucu:
            puan = int(kayit["puan"])
            print(kayit["ad"], puan)
except FileNotFoundError as e:
    print("CSV dosyası bulunamadı:", e)
except KeyError as e:
    print("CSV sütunu eksik:", e)
except ValueError as e:
    print("Sayısal dönüşüm başarısız:", e)
Important

delimiter yanlışsa DictReader satırları doğru sütunlara bölemez. Beklediğiniz sütunlar hiç oluşmayabilir ve sorun sonradan KeyError olarak karşınıza çıkar. Bu yüzden istisnayı yakalamakla yetinmeyin, hatanın kök nedenini (asıl kaynağını) da arayın.

İstisna mı, koşul mu?

Puanın 0 ile 100 arasında olması programın koyduğu bir kuraldır. Bunu if ile denetleriz:

if 0 <= puan <= 100:
    ...

Metnin int() ile sayıya çevrilememesi ise dönüşüm sırasında Python’ın oluşturduğu bir istisnadır. Bunu try/except ile yakalarız:

try:
    puan = int(girdi_metni)
except ValueError:
    ...

raise: fonksiyon sözleşmesi ihlalini açıkça bildirmek

7. haftada assert ile programcı olarak kendi beklentimizi sınamış, kullanıcı girdisini denetlemek için uygun olmadığını söylemiştik. Bir fonksiyon geçersiz bir argümanı program çalışırken açıkça reddetmek istiyorsa raise ile kendisi istisna yükseltebilir:

def saat_ucreti(toplam_ucret, saat):
    if saat <= 0:
        raise ValueError("saat 0'dan büyük olmalı")

    return toplam_ucret / saat

Çağıran kod isterse bunu yakalar:

try:
    print(saat_ucreti(1000, 0))
except ValueError as e:
    print("Geçersiz girdi:", e)

raise ValueError(...) çağıran koda şunu bildirir: verilen değer bu fonksiyonun sözleşmesine uymuyor.

Note

Her geçersiz durumda raise kullanmak zorunda değilsiniz; sıradaki başlıktaki gibi None döndürmek de bir seçenektir. Hangisini seçeceğiniz, çağıran kodun hatayı nasıl karşılayacağına bağlıdır. Önemli olan, fonksiyonun sözleşmesinin açık ve tutarlı olmasıdır.

None ile hata sinyali: kolay ama yükü çağırana bırakır

Aşağıdaki fonksiyon puan geçersizse None döndürüyor:

def puani_coz(metin):
    try:
        puan = int(metin)
    except ValueError:
        return None

    if 0 <= puan <= 100:
        return puan

    return None

Avantajı: istisna yükselmez; çağıran kod sonucu sıradan bir dönüş değeri gibi alır ve kendisi kontrol eder.

Bedeli: fonksiyonu çağıran her yer None olasılığını hesaba katmak zorundadır.

puan = puani_coz("abc")
# print(puan + 10)  # TypeError: None ile int toplanamaz

Bu durumda hata dönüşüm satırında değil, daha ileride, nereden geldiği belli olmayan bir satırda çıkabilir.

Bu yüzden çağıran kod sözleşmeye uyar ve sonucu kullanmadan önce denetler:

puan = puani_coz("abc")

if puan is None:
    print("Puan çözülemedi")
else:
    print("Yeni puan:", puan + 10)

Neden is None?

Python’da tek bir None nesnesi vardır. Bu yüzden önerilen kontrol şöyle yazılır:

if sonuc is None:
    ...

if sonuc is not None:
    ...

sonuc == None yerine is None yazılır. is, iki tarafın aynı nesneyi gösterip göstermediğini sınar; en sık kullanıldığı yer de None kontrolüdür.

Important

14. haftadaki bütünleştirici uygulamada if kayit is None: ve assert ... is None satırlarını göreceksiniz. Orada == yerine is bilerek seçildi: None için kimlik kontrolü yapılıyor.

None mı raise mı?

İki yol da duruma göre doğru olabilir:

None döndürme
→ geçersizlik beklenen bir sonuç seçeneği olabilir
→ çağıran her seferinde kontrol etmelidir

raise ValueError
→ sözleşme ihlalini akıştan ayırır
→ çağıran isterse uygun sınırda except ile yakalar

Bu derste iki yolu da kullanıyoruz. Benzer problemlerde ikisini rastgele karıştırmıyor, hangisini seçtiğimizi fonksiyonun sözleşmesinde açıkça yazıyoruz.

Traceback okumak

Traceback (most recent call last):
  File "rapor.py", line 12, in <module>
    toplam = fiyat_hesapla("abc")
  File "rapor.py", line 5, in fiyat_hesapla
    fiyat = float(metin)
ValueError: could not convert string to float: 'abc'

Bir traceback’i şu sırayla okuyun:

  1. En alttaki hata türünü bulun.
  2. Hata mesajını okuyun.
  3. Kendi dosyanıza ait en alttaki satırı bulun.
  4. O satıra hangi değerlerin geldiğini kontrol edin.
  5. Sorunu daha küçük bir örnekle yeniden üretin.

Sistematik hata ayıklama

  1. Yeniden üret: Hata hangi girdiyle oluşuyor?
  2. Beklenen davranışı yaz: Ne olmalıydı?
  3. Küçült: Hatayı gösteren en küçük örneği bulun.
  4. Gözlemle: Değişkenlerin değerlerine ya da traceback’e bakın.
  5. Hipotez kur: Hatanın nedeni hakkında tek bir tahmin seçin.
  6. Tek değişiklik yap: Yalnızca bu tahmini sınayacak küçük bir düzeltme yapın.
  7. Yeniden doğrula: Hem sorunlu hem sorunsuz girdiyi deneyin.

Bu adımları izleyen biri satırları rastgele değiştirmez; her adımda neyi sınadığını bilir.

Modül nedir?

Modül, fonksiyon ve değer tanımlarını bir arada tutan bir Python dosyasıdır. Bir modülü import ile programınıza alır, içindekileri kullanırsınız. Standart kütüphaneden bir örnek:

import math

print(math.sqrt(81))
print(math.pi)

Tarih işlemleri için datetime modülü:

from datetime import date

bugun = date.today()
print(bugun)

Karekök, π sayısı ya da bugünün tarihi için kendi kodunuzu yazmanız gerekmez; bu işler standart kütüphanedeki modüllerde hazır bulunur.

Tahmin et ve çalıştır: math

İkinci print, 8. haftada gördüğümüz f-string biçimlendirmesiyle sonucu iki ondalık basamakla yazdırır.

Kendi modülümüz

Kendi yazdığınız her .py dosyası da bir modüldür. Örneğin hesaplar.py dosyası:

def kdv_hesapla(tutar, oran):
    return tutar * oran

def indirimli_fiyat(fiyat, oran):
    return fiyat - fiyat * oran

Aynı klasördeki başka bir dosyadan bu modülü şöyle kullanırsınız:

import hesaplar

print(hesaplar.kdv_hesapla(500, 0.20))

Modülden yalnızca bir fonksiyonu da alabilirsiniz:

from hesaplar import kdv_hesapla
print(kdv_hesapla(500, 0.20))

Main guard

Bir Python dosyasının doğrudan çalıştırılması ile modül olarak import edilmesinde main guard davranışı.

main guard ve import davranışı

Aşağıdaki if __name__ == "__main__": kalıbına main guard denir:

def main():
    print("Program başladı")

if __name__ == "__main__":
    main()

Bu kalıp iki durumu birbirinden ayırır:

  • Dosya doğrudan çalıştırılırsa main() çağrılır.
  • Dosya başka bir dosyadan modül olarak içe aktarılırsa (import) main() kendiliğinden çağrılmaz.

Alıştırma: modül fonksiyonunu kullanın

Beklenen sonuç 5.0’dır.

import math

def hipotenus(a, b):
    return math.sqrt(a ** 2 + b ** 2)

Mantık hatasında assert

def indirimli_fiyat(fiyat, oran):
    return fiyat * oran

assert indirimli_fiyat(100, 0.20) == 80

Fonksiyon çalışır ve istisna oluşmaz, ama 80 yerine 20.0 döndürür. assert satırı beklenen değeri gerçek sonuçla karşılaştırır ve AssertionError verir; hata böylece fark edilir. Doğru fonksiyon:

def indirimli_fiyat(fiyat, oran):
    return fiyat - fiyat * oran

Üret: güvenli puan dönüştürme

Fonksiyon şu kurallara uysun:

  • Metin tam sayıya çevrilemiyorsa None döndürür.
  • Sayı 0–100 arasındaysa sayının kendisini döndürür.
  • Sayı bu aralığın dışındaysa None döndürür.
  • Fonksiyonun içinde print() kullanılmaz.

Beklenen çıktı: 85, None, None.

def puani_coz(metin):
    try:
        puan = int(metin)
    except ValueError:
        return None

    if 0 <= puan <= 100:
        return puan

    return None

Fonksiyon çalışınca sonuçları yazdırmakla kalmayın, sözleşmeyi assert ile de sınayın:

assert puani_coz("85") == 85
assert puani_coz("abc") is None
assert puani_coz("120") is None

Hata ayıklama kontrol listesi

  • Hata türü nedir: söz dizimi, çalışma zamanı, mantık?
  • Sorunu aynı girdiyle yeniden üretebiliyor muyum?
  • Beklenen sonuç nedir?
  • Sorunu daha küçük örneğe indirebilir miyim?
  • Traceback hangi hata türünü, mesajı ve satırı gösteriyor?
  • O satırdaki değişkenlerin değerleri nedir?
  • except ... as e ile gerçek mesajı görmem yararlı olur mu?
  • None döndürebilen bir fonksiyonun sonucunu çağıran kod kontrol ediyor mu?
  • Tek bir hipotezi sınayacak küçük bir değişiklik yapabilir miyim?
  • Düzeltme sonrası hem sorunlu hem normal örneği yeniden denedim mi?

Sınav provası

Önce kendi cevabınızı seçin, sonra cevap anahtarında her şıkkın neden doğru ya da yanlış olduğunu okuyun. Yanlış şıklar rastgele yazılmadı; bu konuda öğrencilerin gerçekten yaptığı hatalardan seçildi. Sınav soruları da aynı yolla hazırlanır.

Madde 1. Söz dizimi hatası, çalışma zamanı hatası ve mantık hatası nasıl ayrılır?

  • A. Söz dizimi hatası yalnızca büyük ve karmaşık programlarda çıkar
  • B. Mantık hatası da çalışırken çıkar ve her zaman bir mesaj verir
  • C. Çalışma zamanı hatası kod çalışmadan, söz dizimi hatası çalışırken çıkar; mantık hatası mesaj vermez
  • D. Söz dizimi hatası kod çalışmadan, çalışma zamanı hatası çalışırken çıkar; mantık hatası mesaj vermez
  • E. Üçü de programı hemen durdurur; yalnızca mesajları farklıdır

Madde 2. Bir daire çevresi fonksiyonu math.pi * yaricap döndürüyor. Program hata vermiyor ama sonuçlar hep olması gerekenin yarısı çıkıyor. Bu nasıl bir hatadır?

  • A. Çalışma zamanı hatası
  • B. Kodlama hatası
  • C. Mantık hatası
  • D. Söz dizimi hatası
  • E. ValueError

Madde 3. Aşağıdaki kod neden sorunludur?

try:
    puan = int(satir["puan"])
except:
    puan = 0
  • A. Sorun yok; geniş except daha güvenlidir
  • B. try bloğu tek satırdan oluştuğu için
  • C. puan değişkeni iki farklı yerde atandığı için
  • D. int() çağrısı try içinde kullanılamaz
  • E. except tür belirtmediği için her istisnayı yakalar

Madde 4. CSV işleyen bir programda “dosya yok” ve “beklenen sütun yok” durumları sırasıyla hangi istisnalara karşılık gelir?

  • A. FileNotFoundError ve KeyError
  • B. İkisinde de OSError çıkar
  • C. ValueError ve TypeError
  • D. IndexError ve NameError
  • E. KeyError ve FileNotFoundError

Madde 5. raise ValueError(...) ile assert arasındaki kullanım farkı nedir?

  • A. raise yalnızca try bloğu içinde kullanılabilir
  • B. assert programı hiçbir zaman durdurmaz
  • C. assert çağıran koda hata bildirir; raise yalnızca test içindir
  • D. raise çağırana hata bildirir, assert kendi beklentinizi sınar
  • E. İkisi de aynıdır; raise yalnızca daha okunaklıdır

Madde 6. None denetimi neden sonuc == None yerine sonuc is None biçiminde yazılır?

  • A. None bir sayı olduğu için == uygun değildir
  • B. is daha hızlı olduğu için zorunludur
  • C. None tek bir nesnedir; is aynı nesne olup olmadığına bakar
  • D. == None yazımı hata verir
  • E. İkisi farklı sonuç verir; is None her zaman True döner

Madde 7. Bir traceback okurken hangi üç bilgiyi aramak yararlıdır?

  • A. Python sürümü, işletim sistemi ve dosya boyutu
  • B. Programın çalışma süresi, bellek kullanımı ve çıkış kodu
  • C. Yalnızca en üstteki satır; gerisi önemsizdir
  • D. Değişken adları, tür adları ve girinti düzeyi
  • E. Hata türü, hata mesajı ve kendi kodunuzda geçen en alttaki satır

Madde 8. import math satırı ne yapar?

  • A. math modülünü yükler; adlara math.pi gibi erişilir
  • B. math içindeki bütün adları doğrudan kullanılabilir yapar
  • C. math adlı bir dosya oluşturur
  • D. Programın matematik işlemlerini hızlandırır
  • E. math modülünü internetten indirir

Madde 9. if __name__ == "__main__": satırı hangi iki kullanımı birbirinden ayırır?

  • A. Söz dizimi hatası ile çalışma zamanı hatasını
  • B. Dosyanın doğrudan çalıştırılması ile içe aktarılmasını
  • C. Yerel değişken ile küresel değişkeni
  • D. Fonksiyon tanımı ile fonksiyon çağrısını
  • E. Dosyanın okuma kipi ile yazma kipini

Madde 1. Doğru: D. Söz dizimi hatasında Python kodu çalıştırmaya hiç başlamaz. Çalışma zamanı hatası kod çalışırken çıkar. Mantık hatası mesaj vermez ama sonuç yanlış olur. En tehlikelisi mantık hatasıdır, çünkü program sorunsuz çalışıyor gibi görünür ve yanlışlık ancak sonuç denetlenirse fark edilir.

  • A yanlış: Uzun kodda yazım yanlışı yapmak daha kolay olduğu için akla yatkın gelir. Ama söz dizimi hatası tek satırlık bir kodda da çıkabilir.
  • B yanlış: “Hata” sözcüğü bir mesaj beklentisi doğurur. Ama mantık hatası mesaj vermez; bu yüzden bulunması da zordur.
  • C yanlış: İki hata da traceback ile görüldüğü için hangisinin ne zaman çıktığı karışabilir. Ama roller ters yazılmış: kod çalışmaya başlamadan yakalanan, söz dizimi hatasıdır. Çalışma zamanı hatası ancak kod çalışırken çıkar.
  • E yanlış: İlk iki hata gerçekten programı durdurduğu için üçüncüsünün de öyle davranacağı sanılır. Ama mantık hatası programı durdurmaz ve mesaj vermez.

Madde 2. Doğru: C. Formül eksik yazılmış; doğrusu 2 * math.pi * yaricaptır. Kod geçerli ve çalışıyor; yanlış olan yalnızca hesabın kendisi. Bu tür hatalar ancak sonuç kontrol edilirse fark edilir.

  • A yanlış: Sorun program çalışırken fark edildiği için akla yatkın gelir. Ama program hata vermeden tamamlanıyor; çalışma zamanı hatası programı durdururdu.
  • B yanlış: Günlük dilde “kodda hata” anlamında söylendiği için cazip gelir. Ama kodlama (encoding) karakterlerin baytlara çevrilmesiyle ilgilidir; burada sorun formülde.
  • D yanlış: Formülde bir parça eksik olduğu için yazım yanlışı gibi görünür. Ama Python kodu sorunsuz okuyor ve çalıştırıyor.
  • E yanlış: Değer yanlış çıktığı için ada bakıp bu istisna seçilebilir. Ama hiçbir istisna oluşmuyor.

Madde 3. Doğru: E. Yanlış yazılmış bir değişken adından bellek sorununa kadar her istisna yakalanır; gerçek hatalar fark edilmeden gizlenir. Beklenen istisnalar açıkça yazılmalıdır, örneğin except (ValueError, KeyError):. Yoksa bambaşka bir hata da 0 puana dönüşür.

  • A yanlış: Program hiç durmadığı için güvenli görünür. Ama geniş except hataları gizler ve yanlış sonucu fark etmeyi zorlaştırır.
  • B yanlış: Kısa bir try bloğu eksik yazılmış gibi görünebilir. Ama tek satırlık try bloğu önerilen bir uygulamadır; sorun exceptte.
  • C yanlış: Aynı ada iki atama görmek çakışma gibi görünür. Ama atama iki ayrı kolda yazılmış; hangisi çalışırsa puan onun değerini alır. Bunda sorun yok.
  • D yanlış: Hata verebilecek bir çağrının korumalı bloğa konamayacağı düşünülebilir. Ama tersine, int() çağrısı hata verebileceği için zaten try içine alınır.

Madde 4. Doğru: A. Bulunamayan dosya FileNotFoundError, kayıt sözlüğünde olmayan sütun adı KeyError verir.

  • B yanlış: Eksik sütun bir işletim sistemi hatası değildir.
  • C yanlış: ValueError dönüştürülemeyen değerde, TypeError uyumsuz türde çıkar.
  • D yanlış: IndexError liste dışındaki bir indekste, NameError tanımlanmamış bir adda çıkar.
  • E yanlış: İki istisna ters eşleştirilmiş.

Madde 5. Doğru: D. raise, sözleşmeye uymayan değeri çağıran koda bildirir ve programın gerçek kullanımında da çalışır. assert geliştirme sırasında kendi beklentinizi hızlıca sınamak içindir. assert kontrolleri Python’ı çalıştırırken verilen bir seçenekle kapatılabilir; bu yüzden girdi denetimi asserte bırakılmaz.

  • A yanlış: İstisnalar genellikle try ile birlikte anlatıldığı için akla yatkın gelir. Ama raise bir try bloğunun dışında da kullanılabilir.
  • B yanlış: assert yalnızca bir denetim gibi göründüğü için zararsız sanılabilir. Ama koşul yanlışsa AssertionError verir ve program durur.
  • C yanlış: İki araç da hata bildirdiği için rolleri kolayca karışır. Ama roller ters yazılmış: testte ve geliştirmede assert, çağırana bildirmede raise kullanılır.
  • E yanlış: İkisi de koşul bozulunca bir istisna yükselttiği için aynı iş sanılabilir. Ama amaçları ve kullanım yerleri farklıdır.

Madde 6. Doğru: C. is iki tarafın aynı nesne olup olmadığına bakar. Bu yüzden == işlecinin davranışı değiştirilmiş türlerde de yanıltmaz. Python’ın yazım kılavuzu PEP 8 de bu yazımı önerir. is None niyeti doğrudan anlatır.

  • A yanlış: None çoğu zaman 0 ile karıştırıldığı için sayı sanılabilir. Ama None sayı değildir; “değer yok” anlamına gelen ayrı bir nesnedir.
  • B yanlış: is gerçekten biraz daha hızlıdır, bu yüzden gerekçe gibi görünür. Ama asıl gerekçe hız değil, doğruluk ve okunabilirliktir; zorunluluk da yoktur.
  • D yanlış: Önerilmeyen bir yazımın yasak olduğu düşünülebilir. Ama == None hata vermez; yalnızca önerilen yazım değildir.
  • E yanlış: İki yazımın farklı olması sonuçlarının da farklı olacağını düşündürür. Ama is None yalnızca değer gerçekten None ise True döner.

Madde 7. Doğru: E. Traceback’in en alt satırı türü ve mesajı verir. Kütüphane satırları arasından kendi dosyanızı bulmak da bakılacak yeri daraltır.

  • A yanlış: Bunlar hatanın nedenini bulmaya yardım etmez.
  • B yanlış: Traceback bu bilgileri vermez.
  • C yanlış: En üst satır genellikle en dıştaki çağrıdır; en açıklayıcı bilgi altta durur.
  • D yanlış: Bunlar dolaylı ipuçları olabilir ama traceback’in ana bilgileri değildir.

Madde 8. Doğru: A. import math modülü programa dâhil eder; içindeki adlara modül adıyla erişilir. math.pi yazılınca kodu okuyan kişi pi adının hangi modülden geldiğini görür.

  • B yanlış: Modül yüklendiği için içindekilerin hemen kullanılabileceği sanılır. Ama bu from math import * davranışıdır ve önerilmez; import math sonrası math. öneki gerekir.
  • C yanlış: Modüllerin dosya olduğu öğrenilince import satırının dosya açtığı düşünülebilir. Ama dosya oluşturmaz; var olan modülü yükler.
  • D yanlış: Modülün adı matematik olduğu için hesapları iyileştireceği sanılabilir. Ama import bir hızlandırma aracı değildir.
  • E yanlış: Bazı paketler pip ile indirildiği için akla yatkın gelir. Ama math standart kütüphanenin parçasıdır; Python ile birlikte gelir.

Madde 9. Doğru: B. Dosya doğrudan çalıştırılabilir ya da başka bir dosyadan modül olarak içe aktarılabilir. Main guard bu ikisini ayırır; böylece modülü import eden bir dosya, o modülün deneme kodlarını istemeden çalıştırmaz.

  • A yanlış: Main guard hata ayıklama bölümünde anlatıldığı için hatalarla ilişkilendirilebilir. Ama hata türleriyle ilgisi yoktur.
  • C yanlış: __name__ özel bir ad olduğu için kapsamla ilgili sanılabilir. Ama kapsam ayrımı farklı bir konudur.
  • D yanlış: Main guard’ın altında çoğu zaman bir fonksiyon çağrısı durduğu için akla yatkın gelir. Ama tanımı def satırı, çağrıyı adın yanındaki parantezler belirler.
  • E yanlış: Satırda "__main__" gibi tırnaklı bir metin geçtiği için dosya kipleri akla gelebilir. Ama dosya kipleri open() çağrısına aittir.

Tek sayfa özet

  • Söz dizimi hatası kod çalışmadan önce yazımda, çalışma zamanı hatası kod çalışırken, mantık hatası ise yanlış sonuçta ortaya çıkar.
  • Mantık hatasında program çalışır ama sonuç yanlıştır; daire_cevresi örneğinde doğru formül 2 * math.pi * yaricaptır.
  • try/except ile beklediğiniz belirli istisnaları yakalarsınız; türü yazılmamış geniş except gerçek hataları gizleyebilir.
  • except ... as e ile istisnanın mesajını okuyabilirsiniz.
    1. haftadaki eksik dosya, eksik sütun ve sayıya çevrilemeyen değer sorunları sırasıyla FileNotFoundError, KeyError ve ValueError ile yakalanabilir.
  • raise ValueError(...), sözleşmeye uymayan bir değeri çağıran koda açıkça bildirir.
  • Hata sinyali olarak None döndürülebilir; bunun bedeli, çağıranın her seferinde is None kontrolü yapmasıdır.
  • None için önerilen kontrol is None / is not None biçimidir.
  • Traceback’i okumaya en alttaki hata türü ve mesajdan başlayın, sonra kendi kodunuzdaki satırı bulun.
  • Hata ayıklarken sorunu yeniden üretir, küçültür, gözlemler, bir hipotez kurar ve düzeltmeyi doğrularsınız.
  • Standart kütüphane modülleri import ile kullanılır; kendi yazdığınız Python dosyaları da birer modüldür.
  • Main guard, dosyanın doğrudan çalıştırıldığı durumu modül olarak içe aktarıldığı durumdan ayırır.

Son bölümde yeni kavram yok. İlk 13 haftanın araçlarıyla CSV okuyan, modüllere ayrılmış, hataları yakalayan, koleksiyonlarla çalışan ve kendini assert ile sınayan küçük bir uygulama yazacağız.

Bu bölümün kazanımları

Bu bölümü bitiren öğrenci:

  • Söz dizimi, çalışma zamanı ve mantık hatasını birbirinden ayırır.
  • try / except ile belirli bir istisnayı yakalar ve geniş except riskini bilir.
  • FileNotFoundError, KeyError ve ValueError’ı doğru duruma eşler.
  • raise ile sözleşme ihlalini bildirir ve bunu assertten ayırır.
  • None sinyalini kullanır ve is None denetimini uygular.
  • Traceback’ten hata türünü, mesajı ve hatanın kendi kodundaki yerini okur.
  • import ile modül kullanır ve main guard’ın ne ayırdığını açıklar.
Back to top