İ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.

Python böyle bir durumda devam edemeyeceğini bir istisna (exception) ile bildirir. Bu hafta program çalışırken çıkan istisnaları try/except ile yakalamayı, gerektiğinde raise ile kendiniz istisna yükseltmeyi ve Python’la birlikte gelen hazır fonksiyon dosyalarını, yani modülleri kullanmayı göreceğiz. Hata ararken de rastgele değil, adım adım ilerleyeceğiz.

Bu sayfadaki kod hücreleri kendiliğinden çalışmaz. Her hücrede önce çıktıyı tahmin edin, sonra Run Code düğmesine basın. Kodu değiştirip yeniden çalıştırabilir, Start Over ile ilk hâline döndürebilirsiniz.

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ı yakalama 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. İleride karşınıza çıkar, ama bu derste ezberlemeniz beklenmiyor.

Not dosyasını okuyan programa hangi talimatları verirdiniz?

Her hafta sınıf temsilcisi öğretim elemanına notlar.csv adında bir dosya gönderiyor. Dosyada her öğrencinin adı ve puanı var. Bir program bu dosyayı okuyup sınıfın ortalamasını yazacak. Dosya her hafta düzgün gelmiyor. Geçen dönem şunlar yaşandı:

  1. Temsilci dosyayı göndermeyi unuttu: klasörde notlar.csv yok.
  2. Bir öğrencinin puanı yerine girmedi yazılmış.
  3. Temsilci tabloyu başka bir dosyadan kopyalamış: sütunun adı puan değil, not.
  4. Bir öğrencinin puanı -5 yazılmış.
  5. Program hiçbir uyarı vermeden ortalamayı 32.5 yazdı. Geçerli puanların ortalamasını elle hesaplayınca 65 çıkıyor.

Programın her durumda ne yapacağını 1. bölümdeki sözde kodla, Türkçe ve madde madde yazın. Program dursun mu, o satırı atlayıp devam mı etsin, size ne yazsın?

Sonra kurallarınızı bir denemeden geçirin. Biri bütün durumlar için tek bir kural öneriyor: “Bir sorun çıkarsa o öğrencinin puanını 0 say ve devam et.” Bu kural beşinci durumu açıklar mı? Üçüncü durumda ortalama kaç çıkar? Bu kuralla programın bir sorun olduğunu size haber verdiği bir durum kalır mı?

Python bilmeniz gerekmiyor: “Dosya yoksa ‘dosya bulunamadı’ yaz ve dur” da bir kural. Kurallarınızı bir kenara yazın. Bölümde her birinin Python’da nasıl yazıldığını göreceğiz. Alıştırmalardan önce listenize döneceğiz.

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ı

Aşağıdaki kodun yazımı kurallara uygun. Hücre hangi satırları yazar?

Sorun ancak satır çalıştığında ortaya çıkar. Bu yüzden bu tür hataya çalışma zamanı hatası denir. 10 / 0 satırı ZeroDivisionError, [1, 2][5] satırı IndexError verir. İkinci satırı bunlarla değiştirip deneyin.

Mantık hatası

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

Doğru formülde π sayısı için math.pi değerini kullanabiliriz. math, Python’la birlikte kurulan hazır modüllerden, yani standart kütüphaneden biridir. Aşağıdaki hücrede son satır doğru sonucu beklenen değerle karşılaştırıyor. Hücre bir şey yazar mı?

Python mantık hatasını fark etmez. Sonucu beklenen değerle karşılaştırmak size düşer. Son satırdaki assert da bunu yapar: koşul doğruysa hiçbir şey yazmaz, yanlışsa AssertionError verir.

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

Yakalanmayan istisna programı durdurur

Python bir satırı çalıştırırken devam edemeyeceği bir durumla karşılaşırsa bir istisna yükseltir. İstisna yakalanmazsa program o noktada durur. Hücre kaç satır yazar?

Hücrenin altında çıkan döküme hata iz dökümü (traceback) denir. Traceback, hatanın hangi satırlardan geçerek oluştuğunu gösterir. En alt satırı türü ve mesajı verir: ValueError, "on" metninin tam sayıya çevrilemediğini söyler.

try / except

try bloğuna hata verebilecek satırları, except bloğuna hata çıkarsa yapılacak işi yazarız. Hücre ne yazar? Sonra metin değerini "abc" yapıp yeniden tahmin edin.

try bloğundaki satırlar sırayla çalışır. Bir satır ValueError yükseltirse bloğun kalanı atlanır ve except ValueError bloğu çalışır.

"42" için dönüşüm başarılıdır ve Sayı: 42 yazılır. except bloğu çalışmaz. "abc" için int() hata verir, print("Sayı:", sayi) satırı atlanır ve yalnız Geçerli bir tam sayı değil yazılır.

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. e, oluşan istisna nesnesine bu blok içinde verdiğimiz addır. Ayrıntı: satırında ne görürsünüz?

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 ile sorunun ayrıntısını görürsünüz.

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: Puan: satırı yazılır mı?

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

Not dosyasındaki ikinci durum: puan yerine girmedi yazılmış. Aşağıdaki kod bu metinde durur.

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

Hata veren satır int(girdi_metni). Onu ve ardından gelen print() satırını try bloğuna alın.

girdi_metni = "girmedi"

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 hataları da yakalar ve program hiçbir uyarı vermeden devam eder:

try:
    ...
except:
    ...

Aşağıdaki kayıtta sütunun adı puan değil, not. Programcı yalnız sayıya çevrilemeyen puanı düşünmüş ve türsüz bir except yazmış. Hücre ne yazar? Program size bir sorun olduğunu söylüyor mu?

0 yazılır. kayit["puan"] satırı KeyError yükseltir, çünkü sözlükte "puan" anahtarı yok. Türsüz except bu hatayı da yakalar ve puanı 0 yapar. Ali’nin puanı 85 olduğu hâlde program hata vermeden 0 kullanır.

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

try:
    puan = int(kayit["puan"])
except ValueError:
    ...

Kodu okuyan kişi hangi hatanın beklendiğini görür. Beklenmeyen KeyError ise yakalanmaz ve traceback onu gösterir. Yukarıdaki hücrede except: satırını except ValueError: yapıp deneyin.

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ü

Her türü ayrı bir except bloğunda yakaladığınızda hatanın nedenini ayırt edebilirsiniz. Hücrede hangi blok çalışır? Sonra çağrıyı bol("yirmi", 2) yapıp yeniden deneyin.

Python except bloklarına yukarıdan aşağı bakar ve hatanın türüne uyan ilk bloğu çalıştırır.

CSV okurken çıkan üç hata

12. bölümde 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

Bu sayfadaki hücrelerin yanında notlar.csv adında bir dosya yok. Hücre ne yazar?

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 yok

DictReader’ın verdiği kayıtta "puan" sütunu yoksa kayit["puan"] erişimi KeyError verir. e bu kez neyi yazar?

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

import csv

try:
    with open("notlar.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. int("-5") hata vermez, çünkü -5 geçerli bir tam sayıdır. Puanın -5 olamayacağını Python değil, siz bilirsiniz. Bu kuralı if ile denetleriz:

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

Metnin int() ile sayıya çevrilememesi ise dönüşüm sırasında Python’ın yükselttiği 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 bir fonksiyonun ne beklediğini ve ne döndürdüğünü anlatan yazılı nota sözleşme demiştik. assert ile de 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. Hücre kaç satır yazar?

raise ValueError(...) çağıran koda şunu bildirir: verilen değer bu fonksiyonun sözleşmesine uymuyor. Çağıran kod isterse bunu except ile yakalar.

İki satır yazılır: 250.0 ve Geçersiz girdi: saat 0'dan büyük olmalı. İkinci çağrıda raise satırı çalışır, try bloğunun kalanı atlanır. Bu yüzden Hesap bitti yazılmaz.

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. Seçtiğiniz yolu fonksiyonun sözleşmesine yazın ve bütün geçersiz durumlarda aynı yolu kullanın.

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. Son satır ne yapar?

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. Hücrede hata dönüşüm satırında değil, daha ileride çıktı: None ile bir sayı toplanamadığı için TypeError verdi. Büyük bir programda böyle bir hatanın nereden geldiği hemen belli olmaz.

Bu yüzden çağıran kod sözleşmeye uyar ve sonucu kullanmadan önce denetler. Hücre ne yazar? Sonra "abc" yerine "85" yazıp deneyin.

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 yerde 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 oluşturun.

Bu örnekte hata rapor.py dosyasının 5. satırında, float("abc") çağrısında çıkıyor. 12. satır, o fonksiyonu çağıran satırdır.

Hata ayıklamanın yedi adımı

  1. Yeniden oluştur: Hata hangi girdiyle çıkıyor?
  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. Bir neden seç: 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: hücre hangi iki sayıyı yazar?

Tarih işlemleri için datetime modülü var. Hücre bugünün tarihini yazar:

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

İki print() ne yazar? İkincisi, 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()

Bir dosyayı başka bir dosyadan import ile kullanmaya içe aktarmak denir. Main guard 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 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

Fonksiyon 100 TL’lik ürüne %20 indirim uygulayıp 80 döndürmeli. Hücre çalışınca ne olur?

Fonksiyon çalışır ve kendi içinde istisna yükselmez, 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. Mantık hatası böylece fark edilir. Doğru fonksiyon:

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

Soruya dönelim: not dosyasındaki beş durum Python’da

Bölümün başında not dosyasını okuyan programa talimat yazmıştınız. Beş durumun Python’daki karşılıkları şöyle:

Durum Sözde kodda Python’da Dikkat
notlar.csv yok “Dosya yoksa ‘notlar.csv bulunamadı’ yaz ve dur” except FileNotFoundError: Çalışma zamanı hatası. Yakalanmazsa traceback dosyanın adını gösterir
Puan yerine girmedi “Puan sayı değilse o öğrenciyi atla ve kimi atladığını yaz” int() ValueError yükseltir, except ValueError: yakalar Atlanan öğrenciyi 0 saymak ortalamayı düşürür
Sütunun adı not “Puan sütunu yoksa dur ve hangi sütunun bulunamadığını yaz” except KeyError as e: “Sorun çıkarsa 0 say” kuralı burada bütün sınıfa 0 verir ve ortalama 0 çıkar. Türsüz except tam olarak bu kuraldır
Puan -5 “Puan 0 ile 100 arasında değilse geçersiz say” if 0 <= puan <= 100: denetimi. Fonksiyon geçersiz puanda None döndürür ya da raise ValueError(...) ile bildirir int("-5") hata vermez. Kuralı programcı koyar. None dönüyorsa çağıran is None ile denetler
Ortalama 32.5, olması gereken 65 “Sonucunu bildiğim küçük bir dosyayla dene, sonuçları karşılaştır” assert ortalama == 65 Mantık hatası mesaj vermez. Burada geçersiz puanlar 0 sayılıp bölmeye katılmış

Listenizi tabloyla karşılaştırın. Bütün durumlara tek bir “sorun çıkarsa 0 say” kuralı yazdıysanız üçüncü ve beşinci satıra bakın: program hiç durmadan yanlış bir ortalama yazar ve size haber vermez. Her durum için ayrı bir kural yazdıysanız Python’da her biri ayrı bir except bloğuna ya da if denetimine karşılık gelir.

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

Not dosyasındaki ikinci ve dördüncü durumu bir fonksiyonda çözelim. Fonksiyon dosyadan gelen puan metnini alacak.

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("girmedi") is None
assert puani_coz("-5") is None

Sıra sizde: sınıf ortalaması

Aşağıdaki liste, notlar.csv dosyasından okunmuş dört kaydı taklit ediyor. puani_coz() fonksiyonunu kullanarak yalnız geçerli puanların ortalamasını hesaplayın ve atlanan öğrencilerin adını yazdırın. Son satırdaki assert, beşinci durumdaki hatanın tekrar etmediğini sınar.

Başlangıç kodu henüz hiçbir puanı saymadığı için sayi 0 kalır ve son satırlarda ZeroDivisionError verir. Döngüyü yazınca bu hata kaybolur. Beklenen çıktı: Atlandı: Ece, Atlandı: Can ve Ortalama: 65.0.

Döngüde puan = puani_coz(kayit["puan"]) yazın. puan is None ise adı yazdırın, değilse toplam’a ekleyip sayi’yı bir artırın.

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

    if 0 <= puan <= 100:
        return puan

    return None

kayitlar = [
    {"ad": "Ali", "puan": "85"},
    {"ad": "Ece", "puan": "girmedi"},
    {"ad": "Can", "puan": "-5"},
    {"ad": "Su", "puan": "45"},
]

toplam = 0
sayi = 0

for kayit in kayitlar:
    puan = puani_coz(kayit["puan"])
    if puan is None:
        print("Atlandı:", kayit["ad"])
    else:
        toplam = toplam + puan
        sayi = sayi + 1

ortalama = toplam / sayi
print("Ortalama:", ortalama)
assert ortalama == 65

Hata ayıklama kontrol listesi

  • Hata türü nedir: söz dizimi, çalışma zamanı, mantık?
  • Sorunu aynı girdiyle yeniden oluşturabiliyor 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 tahmini 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ış: FileNotFoundError gerçekten bir OSError türü olduğu için iki durum aynı hataya bağlanabilir. Ama eksik sütun işletim sistemiyle ilgili değildir; kayıt sözlüğünde olmayan anahtara erişmek KeyError verir.
  • C yanlış: CSV okurken en sık görülen hata ValueError olduğu için her sorun ona bağlanabilir. Ama ValueError dönüştürülemeyen değerde, TypeError uyumsuz türde çıkar. Dosyanın ya da sütunun yokluğu bunlardan biri değildir.
  • D yanlış: Eksik sütun “olmayan bir yere erişmek”, eksik dosya “olmayan bir ad” gibi düşünülebilir. Ama IndexError liste dışındaki bir indekste, NameError tanımlanmamış bir değişken adında çıkar.
  • E yanlış: İki istisna doğru seçilmiş, bu yüzden şık ilk bakışta doğru görünür. Ama sıra ters: dosya yokken FileNotFoundError, sütun yokken KeyError çıkar.

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ış: Bir program bir bilgisayarda çalışıp başkasında çalışmayınca önce ortam akla gelir. Ama traceback bu bilgileri göstermez; hatanın nedeni çoğu zaman satıra gelen değerdedir.
  • B yanlış: Program çöktüğü için performansla ilgili bir sorun aranabilir. Ama traceback bu bilgileri vermez; hata türünü, mesajı ve hatanın geçtiği satırları verir.
  • C yanlış: Metinler genellikle yukarıdan okunduğu için en üst satır en önemlisi sanılır. Ama en üst satır genellikle en dıştaki çağrıdır; hatanın türü ve mesajı en altta durur.
  • D yanlış: Traceback’te kod satırları da göründüğü için oradaki adlara ve girintiye bakılabilir. Bunlar dolaylı ipucu olabilir, ama aranacak üç bilgi en alttaki tür, mesaj ve kendi kodunuzdaki satırdır.

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. Python bunu fark etmez, sonucu assert ile beklenen değerle karşılaştırmak gerekir.
  • Python devam edemediği bir durumda istisna yükseltir. Yakalanmayan istisna programı durdurur ve bir traceback yazdırır.
  • try/except ile beklediğiniz belirli istisnaları yakalarsınız. Türü yazılmamış geniş except gerçek hataları gizler: eksik sütun bile hata vermeden 0 puana dönüşebilir.
  • except ... as e ile istisnanın mesajını okuyabilirsiniz.
  • Eksik dosya, eksik sütun ve sayıya çevrilemeyen değer sırasıyla FileNotFoundError, KeyError ve ValueError ile yakalanır.
  • int("-5") hata vermez. Puanın 0 ile 100 arasında olması gibi kuralları programcı if ile denetler.
  • 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.
  • Traceback’i okumaya en alttaki hata türü ve mesajdan başlayın, sonra kendi kodunuzdaki satırı bulun.
  • Hata ayıklarken sorunu yeniden oluşturur, küçültür, gözlemler, bir neden seçer 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ırt eder.
  • try / except ile belirli bir istisnayı yakalar ve geniş except riskini açıklar.
  • 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 sonucu is None ile denetler.
  • 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