Dosyalar, istisnalar ve sistematik hata ayıklama

Gerçek bir programa her zaman doğru girdi gelmez. Dosya bulunmayabilir, bir satırda sayı yerine metin olabilir ya da program çalışıp yanlış sonuç verebilir. Program çalışırken böyle bir sorun çıkınca Python normal akışı keser ve bir istisna (exception) oluşturur. 1. haftada gördüğünüz ValueError ve TypeError birer istisnaydı. Bu hafta dosyadan okuyup dosyaya yazacak, istisnaları yakalayacak ve gerektiğinde kendimiz yükselteceğiz. Bir hata mesajı gördüğümüzde kodu rastgele değiştirmeyecek, mesajı sorunun nedenini gösteren bir kanıt gibi okuyacağız.

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
  • with open(...) kalıbı ve dosyanın blok bitiminde kapanması
  • Metin dosyalarında neden encoding="utf-8" yazıldığı
  • "r", "w" ve "a" kipleri, "w" kipinin eski içeriği silmesi
  • Belirli istisna türünü yakalama ve istisnayı yakalayıp hiçbir şey yapmamanın zararı
  • raise ile print farkı
  • Söz dizimi, çalışma zamanı ve mantık hatalarının ayrımı
  • Traceback çıktısını hata türünden başlayarak okuma
  • pathlib ve ikili dosya kipleri
  • logging modülü
  • Kendi istisna sınıfını tanımlama (12. bölümün konusu)
  • assert ile raise arasındaki seçim (14. bölümün konusu)

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

Not dosyasını okuyan programı C’de nasıl yazardınız?

Not programı artık notları bir dosyadan okuyacak. notes.txt dosyasının her satırında bir öğrencinin adı ve puanı var: Ayşe,80. Program şu beş işi yapacak:

  1. Dosyayı açıp satır satır okumak, iş bitince dosyayı kapatmak
  2. Sonuç raporunu her çalışmada baştan yazmak, çalışma günlüğüne ise eski kayıtları silmeden eklemek
  3. Dosya yoksa anlaşılır bir mesaj vermek, puan yerine bozuk yazan satırı atlayıp devam etmek
  4. Hiç geçerli not yoksa, ortalamayı hesaplayan fonksiyonun bunu çağırana bildirmesi
  5. Program çöktüğünde ya da yanlış ortalama verdiğinde hatanın yerini bulmak

Programlama Temelleri’nde C ile yazdığınız programları düşünün. Bu işlerin her birini C’de nasıl yapardınız? Okumaya devam etmeden önce her iş için bir satır yazın. Hangi fonksiyonu çağıracağınızı ya da neyi denetleyeceğinizi yazmanız yeter: “fopen ile açarım” da bir cevap.

Bölümde bu beş işin Python’da nasıl yazıldığını göreceğiz. Bölümün sonunda listenize döneceğiz.

with ile dosya açmak

C’de dosyayı fopen ile açar, işiniz bitince fclose ile kapatırdınız. Arada bir return ya da hata olursa fclose satırına hiç gelinmeyebilirdi. Python’da dosya open() ile açılır ve çoğu zaman bir with bloğu içinde kullanılır:

with open("notes.txt", "r", encoding="utf-8") as file:
    content = file.read()

print(content)

open() dosya adını, kipi ve karakter kodlamasını alır, bir dosya nesnesi döndürür. as file bu nesneyi file adına bağlar. file.read() dosyanın bütün içeriğini tek bir string olarak döndürür. with bloğu bittiğinde dosya kapatılır, blok içinde bir istisna oluşsa bile. Elle close() çağırmayı unutma riski kalmaz.

Neden encoding="utf-8" yazıyoruz?

Metin dosyası baytlardan oluşur. Karakterlerin bu baytlara nasıl çevrileceğini bir karakter kodlaması belirler. C’de fopen kodlamayla ilgilenmez, baytları olduğu gibi okur. Python ise metin dosyasını okurken baytları karakterlere çevirir. Kodlamayı yazmazsanız işletim sisteminin varsayılanını kullanır, bu yüzden aynı dosya farklı makinelerde farklı okunabilir. Bu sorun özellikle Windows’ta ve Türkçe ç, ğ, ı, İ, ö, ş, ü karakterlerinde çıkar.

Bu ders boyunca metin dosyalarında kodlamayı açıkça encoding="utf-8" diye yazacağız. Böylece dosyanın hangi kodlamayla okunup yazılacağı makineden makineye değişmez.

Satır satır okuma

C’de dosyayı fgets ile satır satır okurdunuz. Python’da dosya nesnesini bir for döngüsüyle dolaşırsınız: döngü değişkeni her turda bir satırı alır. Kod hücreleri tarayıcının içinde sanal bir dosya sistemi kullanır, bu yüzden dosya deneylerini burada yapabilirsiniz. Hücredeki ilk with bloğu okunacak dosyayı oluşturuyor ("w" kipini bir sonraki başlıkta göreceğiz). İkinci blok dosyayı okuyor. Hücre ne yazar? Her satırın sonundaki \n karakterine ne oluyor?

Kip yazılmazsa open() dosyayı okumak için ("r") açar. Dosyadan gelen her satır satır sonu karakteriyle (\n) biter. 2. haftadaki gibi satırı önce strip() ile temizler, sonra split() ile bölersiniz. Parçalar metin olduğu için puan int() ile sayıya çevrilir.

Bu derste dosyaları çoğunlukla for line in file ile okuyacağız. read() bütün içeriği tek bir metin olarak, readlines() bütün satırları bir liste olarak belleğe alır. Küçük dosyalarda sorun çıkarmazlar, ama satır satır yapılan işlerin çoğunda gerekmezler.

Dosya kipleri: r, w, a

C’deki fopen kipleri Python’da aynı harflerle yazılır:

Kip Anlam Dikkat edilecek nokta
"r" oku dosya yoksa FileNotFoundError
"w" yaz dosya varsa mevcut içeriği silip baştan yazar
"a" sona ekle mevcut içeriği korur, sonuna yazar
Warning"w" kipi eski içeriği siler
with open("odev.txt", "w", encoding="utf-8") as file:
    file.write("Yeni içerik")

odev.txt zaten varsa eski içerik silinir. Var olan dosyanın sonuna eklemek istiyorsanız "a" kullanın. Kipi yazmadan önce kendinize “eski içerik kalmalı mı?” diye sorun.

Not programında sonuç raporu her çalışmada "w" ile baştan yazılır, çalışma günlüğü ise "a" ile açılıp büyür. Aşağıdaki üç with bloğu aynı dosyayı sırayla "w", "a" ve "r" kipiyle açıyor. Son print() kaç satır yazar? Hangileri?

"a" dosyanın sonuna ekler, "w" ise dosyayı her açılışta baştan yazar. Hücreyi bir kez daha çalıştırırsanız ne olur? Satırlar çoğalır mı?

İlk blok dosyaya python ve oop satırlarını yazar. İkinci blok istisna satırını sona ekler. Son blok üç satırı da okur: python, oop, istisna. Hücreyi yeniden çalıştırdığınızda ilk blok dosyayı yine baştan yazdığı için çıktı değişmez.

Hatayı yakalamak: try ve except

C’de fopen dosyayı bulamazsa NULL döndürürdü, siz de if (f == NULL) diye denetlerdiniz. atoi("bozuk") ise hiçbir uyarı vermeden 0 döndürürdü. Python’da iki durumda da istisna oluşur: dosya yoksa FileNotFoundError, sayıya çevrilemeyen metinde ValueError. İstisnayı try ve except ile yakalarsınız. Hücrede raw değişkeni "42x". Hücre ne yazar? print(number * 2) satırı çalışır mı?

try bloğundaki bir satır istisna oluşturursa bloğun geri kalanı atlanır ve türü uyan except bloğu çalışır. as error yakalanan istisnayı error adına bağlar. Hata mesajını yazdırmak ya da ayrıntısına bakmak için bu adı kullanırız.

try bloğunda hata oluşup oluşmamasına göre except ve normal akışın nasıl ilerlediğini gösteren diyagram.

try/except akışı

Eksik dosya için de aynı kalıp kullanılır. Sanal dosya sisteminde missing.txt adlı bir dosya yok. Hücre ne yazar?

except Exception: yazıp her istisnayı yakalamak başta rahat görünebilir. Ama bu, yanlış yazılmış bir ad ya da uyuşmayan türler gibi kodunuzdaki hataları da gizler. Hangi istisnayı bekliyorsanız except satırına onun türünü yazın.

WarningHatayı yakalayıp yok saymayın
try:
    risky_operation()
except Exception:
    pass

Bu kalıp neyin yanlış gittiğini gizler: program hiçbir mesaj vermeden devam eder, ama sonucu yanlış olabilir. Öğrenirken hata mesajını görmek, onu susturmaktan çoğu zaman daha yararlıdır.

else ve finally

try deyiminin tam biçiminde şu bloklar da bulunabilir:

try:
    value = int(raw)
except ValueError as error:
    print("Dönüşüm başarısız:", error)
else:
    print("Dönüşüm başarılı:", value)
finally:
    print("Bu satır her durumda çalışır")
  • else, try bloğu hiç istisna oluşmadan biterse çalışır.
  • finally, istisna oluşsa da oluşmasa da çalışır. Açılan bir dosyayı kapatmak gibi her durumda yapılması gereken işler için kullanılır.

Dosyaları çoğu zaman with ile açtığımız için finally içine elle close() yazmamız gerekmez. Yine de finally başka kodlarda karşınıza çıkacak, ne işe yaradığını bilin.

Hatayı çağırana bildirmek: raise

C’de ortalama fonksiyonu hiç not almadıysa bunu çağırana -1 gibi özel bir değer döndürerek bildirirdi. Çağıran bu değeri denetlemeyi unutursa program -1’i ortalama sanıp devam ederdi. Python’da bir fonksiyon, işini yapamayacağını bir istisna yükselterek bildirir.

Bazı istisnaları Python kendisi yükseltir: int("abc") çalışınca ValueError çıkar. Notu olmayan bir öğrencinin ortalamasının hesaplanamayacağını ise Python bilemez, bunu programın kendi kuralı söyler. Böyle bir kural bozulduğunda istisnayı raise ile kendimiz yükseltiriz. Hücredeki sum() listedeki sayıların toplamını döndürür. Hücre ne yazar? return satırı çalışır mı?

raise ValueError(...) çalıştığı anda fonksiyonun geri kalanı atlanır ve uygun except bloğu aranır. print("hata") ise yalnızca mesaj yazar: fonksiyonu çağıran kod bir sorun olduğunu anlamaz ve program devam eder. raise ise çağırana işlemin normal biçimde tamamlanamadığını bildirir. Çağıran istisnayı yakalamazsa program durur. -1 gibi bir dönüş değeri gözden kaçabilir, yakalanmayan bir istisna kaçmaz.

6–12. haftalarda nesnelerin uyması gereken kuralları (örneğin “bakiye eksiye düşemez”) korurken en çok raise kullanacağız. Nesnenin her zaman uyması gereken bu tür kurallara 8. haftada değişmez koşul (invariant) adını vereceğiz.

Üç hata sınıfını ayırın

Program çöktüğünde ya da yanlış sonuç verdiğinde, hatanın yerini aramadan önce hangi sınıftan olduğunu ayırın. Üçünü de 1. haftada kısaca gördünüz.

Söz dizimi hatası

if score > 50
    print("Geçti")

if satırının sonundaki : eksik. Python kodu okurken takılır ve dosyanın tek satırını bile çalıştırmaz. C’de derleyicinin verdiği söz dizimi hatalarına benzer.

Çalışma zamanı hatası

score = int("seksen")

Satırın yazımı doğrudur ama satır çalışırken sorun çıkar: "seksen" metni tam sayıya çevrilemez ve ValueError yükselir.

Mantık hatası

# Yüzde 20 indirim yapmak isterken:
final = price * 1.20

Program çalışır ama yanlış sonuç verir. Mantık hataları çoğu zaman istisna oluşturmaz. Onları bulmak için sonucu beklenen değerle karşılaştırmak, yani test yazmak ve programı örnek girdilerle denemek gerekir.

Beklenen sonucu assert ile yazmak

assert satırı bir koşulu denetler. Koşul doğruysa hiçbir şey yapmaz, yanlışsa programı AssertionError ile durdurur. Beklenen sonucu bir assert satırına yazarsanız, mantık hatası artık hata vermeden geçmez. Aşağıdaki average fonksiyonu C alışkanlığıyla yazılmış. 70 ve 85’in ortalaması 77.5 olmalı. Hücre ne yazar? Test geçti satırına gelinir mi?

// taban bölmesidir, 155 // 2 işlemi 77 verir. İlk satır 77 yazar. assert satırındaki koşul yanlış olduğu için program AssertionError ile durur ve Test geçti yazılmaz. Düzeltmek için // yerine / yazın.

Sonraki haftaların çalışır kod görevlerinde sonuçları assert satırlarıyla denetleyeceksiniz. assert ile raise arasındaki seçime 14. haftada döneceğiz.

Hata iz dökümü (traceback) nasıl okunur?

C’de sıfıra bölen bir program çoğu zaman hangi satırda çöktüğünü söylemeden kapanırdı. Python’da yakalanmayan bir istisna programı durdurduğunda ekrana şöyle bir döküm yazılır:

Traceback (most recent call last):
  File "app.py", line 12, in <module>
    total = calculate(data)
  File "app.py", line 5, in calculate
    return 100 / data["count"]
ZeroDivisionError: division by zero

İlk bakılacak yer en alttaki satırdır: hata türü ZeroDivisionError. Sonra hemen üstte hatanın oluştuğu kod satırını bulun. Daha yukarıdaki satırlar o noktaya hangi fonksiyon çağrılarıyla gelindiğini gösterir.

Bir Python traceback çıktısında dosya, satır, çağrı zinciri ve hata türünün nasıl okunacağını gösteren diyagram.

Traceback okuma

Hata ayıklama döngüsü

Hata ayıklama (debugging), bir hatanın nedenini bulup düzeltme işidir. Rastgele denemek yerine şu adımları izleyin:

  1. Hatayı tekrarlayın: Hata hangi girdide her seferinde oluşuyor?
  2. Daraltın: Hatayı hâlâ veren en küçük kod parçası hangisi?
  3. Kanıt toplayın: Traceback’i okuyun. C’de printf ile yaptığınız gibi ara değerleri print() ile, türlerini type() ile yazdırın.
  4. Hipotez kurun: Sorunun nedeni ne olabilir?
  5. Tek değişiklik yapın: Aynı anda birkaç şeyi rastgele değiştirmeyin.
  6. Yeniden deneyin: Hata gitti mi? Başka bir şey bozuldu mu?

Nesne Tabanlı Programlama II dersinde aynı adımları debugger (kodu satır satır çalıştırıp değişkenlere bakmanızı sağlayan araç), logging ve testlerle izleyeceğiz.

Soruya dönelim: beş iş Python’da

Bölümün başında not dosyasını okuyan programın beş işini C’de nasıl yapacağınızı sormuştuk. Python’daki karşılıkları şöyle:

İş C’de Python’da Dikkat
Dosyayı satır satır okuyup kapatmak fopen, fgets döngüsü ve fclose with open("notes.txt", encoding="utf-8") as file: ve for line in file: with dosyayı blok bitince kapatır. Kodlamayı açıkça yazın
Raporu baştan yazmak, günlüğe eklemek fopen(..., "w") ve fopen(..., "a") open(..., "w", ...) ve open(..., "a", ...) "w" var olan dosyanın içeriğini siler
Eksik dosya ve bozuk satır fopen sonucunu NULL ile karşılaştırırsınız, atoi bozuk satırda 0 döndürür try ile except FileNotFoundError ve except ValueError Yalnız beklediğiniz türü yakalayın. except Exception: pass hataları gizler
Ortalama hesaplanamıyor -1 gibi özel bir değer döndürürsünüz raise ValueError("Geçerli not yok") Yakalanmayan istisna programı durdurur, gözden kaçmaz
Hatanın yerini bulmak printf ile ara değerleri yazdırırsınız Traceback’i en alttan okumak, print() ve assert Mantık hatası istisna oluşturmaz, sonucu beklenen değerle karşılaştırın

Listenizi tabloyla karşılaştırın. İlk iki satırda C bilginiz neredeyse olduğu gibi işe yarar, kip harfleri bile aynı. Fark üçüncü ve dördüncü satırda. C’de bir sorunu dönüş değeriyle bildirirdiniz ve o değeri denetlemek çağıranın işiydi. Denetlemeyi unutursanız program yanlış değerle devam ederdi. Python’da sorun bir istisnayla bildirilir. Çağıran onu yakalamazsa program traceback’le durur ve sorun gözden kaçmaz.

Bu bölümle Python’a geçiş bitiyor. Beş haftada değerleri ve türleri, kontrol akışını, koleksiyonları, fonksiyonları, modülleri, dosyaları ve istisnaları gördünüz. 6. haftadan itibaren soru değişiyor. “Python’da döngü nasıl yazılır?” yerine “Bir banka hesabının bakiyesi nerede durmalı, onu hangi kod değiştirebilmeli?” diye soracağız. C’de bir struct ile onu değiştiren fonksiyonlar ayrı ayrı dururdu. Nesne yönelimli programlamada (OOP) veri ile onu değiştiren kod aynı yapıda toplanır, raise de o yapının kurallarını korur.

Alıştırma: Doğru hata türünü yakala

except ValueError as error:

Alıştırma: raise ile hata yükselt

Aşağıdaki fonksiyonu tamamlayın. score 0–100 aralığının dışındaysa ValueError yükseltmeli, geçerliyse değeri döndürmelidir:

Fonksiyonu sınırdaki -1, 0, 100 ve 101 değerleriyle ayrı ayrı deneyin.

Alıştırma: Mantık hatasını bul

Program hata vermeden çalışıyor. Ama yüzde 20 indirimde beklenen sonuç 80. Bu hatanın neden istisna oluşturmadığını açıklayın ve fonksiyonu düzeltin. Düzelttikten sonra beklenen sonucu bir assert satırıyla denetleyin.

Alıştırma: Dosya verisini doğrula

Kodu çalıştırmadan önce okuyun. Hangi satır atlanır? values listesi ne olur?

Sonra bozuk yerine 30 yazıp yeniden çalıştırın.

Sıra sizde: Dayanıklı kayıt okuyucu

name,score biçiminde dört satırlık bir dosya oluşturun. Bir satırda geçersiz puan bulunsun. Program şunları yapsın:

  • Dosyayı encoding="utf-8" ile açsın
  • Dosyayı for line in file ile dolaşsın
  • Geçerli kayıtları listeye eklesin
  • Geçersiz satırı except ValueError as error ile yakalayıp açık bir mesajla bildirsin
  • Geçerli puanların ortalamasını yazsın
  • Hiç geçerli kayıt yoksa ortalama fonksiyonu bunu raise ile bildirsin, ana program bu istisnayı yakalayıp mesaj yazsın
  • Sonuç raporunu ayrı bir dosyaya "w" kipiyle, eski içeriğin silineceğini bilerek yazsın

Çalışır kod görevi: Programı üç dosyayla çalıştırın: düzgün bir dosya, bir satırı bozuk bir dosya ve hiç geçerli kaydı olmayan bir dosya. Üçünde de program çökmeden bitmelidir.

Sınav provası

Önce kendi cevabınızı seçin; sonra cevap anahtarında her şıkkın neden doğru veya yanlış olduğunu okuyun. Çeldiriciler uydurma değil, bu konuda gerçekten yapılan hatalardır. Sınav maddeleri de bu mantıkla yazılır.

Madde 1. with open("notes.txt", "r", encoding="utf-8") as file: yazımının elle open() / close() çiftine göre avantajı nedir?

  • A. Dosya yoksa kendiliğinden oluşturur
  • B. Kodlama belirtmeyi gereksiz kılar
  • C. Dosyanın içeriğini kendiliğinden satırlara böler
  • D. Dosyayı belleğe tümüyle yükleyerek okumayı hızlandırır
  • E. Hata oluşsa bile blok bitince dosya kapatılır

Madde 2. İçinde veri bulunan odev.txt dosyası "w" kipiyle açılıp yazılırsa ne olur?

  • A. Dosya zaten var olduğu için FileExistsError yükselir
  • B. Yeni içerik dosyanın sonuna eklenir
  • C. Yeni içerik dosyanın başına eklenir, eskisi aşağı kayar
  • D. Mevcut içerik silinir ve dosya baştan yazılır
  • E. Dosya salt okunur açılır

Madde 3. Var olmayan bir dosyayı "r" kipiyle açmak ne yapar?

  • A. None döndürür
  • B. Boş bir dosya oluşturur
  • C. Boş metin döndürür
  • D. PermissionError yükseltir
  • E. FileNotFoundError yükseltir

Madde 4. Metin dosyalarında encoding="utf-8" yazmayı neden alışkanlık hâline getiriyoruz?

  • A. Dosya boyutunu küçülttüğü için
  • B. Varsayılan kodlama makineden makineye değiştiği için
  • C. Dosya okuma hızını artırdığı için
  • D. Yalnızca ikili dosyalarda gerektiği için
  • E. Python 3’te encoding yazılmazsa dosya açılmadığı için

Madde 5. Yüzde 20 indirim yapmak isterken yazılan final = price * 1.20 satırı hangi hata sınıfına girer?

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

Madde 6. raise ValueError("Yetersiz bakiye") ile print("Yetersiz bakiye") arasındaki temel fark nedir?

  • A. raise mesajı kırmızı renkte yazar
  • B. raise yalnızca fonksiyon içinde, print yalnızca dışında kullanılır
  • C. print daha hızlı çalışır
  • D. raise akışı keser ve hatayı çağırana iletir, print yalnız yazar
  • E. raise programı her durumda sonlandırır

Madde 7. Aşağıdaki program ne yazdırır?

def withdraw(balance, amount):
    if amount > balance:
        raise ValueError("Yetersiz bakiye")
    return balance - amount

try:
    print(withdraw(100, 150))
except ValueError as error:
    print("İşlem reddedildi:", error)
  • A. İşlem reddedildi: None
  • B. -50
  • C. İşlem reddedildi: Yetersiz bakiye
  • D. Program çöker; except bloğu ValueError yakalayamaz
  • E. Önce -50, sonra İşlem reddedildi: Yetersiz bakiye

Madde 8. Aşağıdaki kalıp neden önerilmez?

try:
    risky_operation()
except Exception:
    pass
  • A. Kodunuzdaki hatalar da iz bırakmadan kaybolur
  • B. Exception sınıfı yakalanamaz
  • C. pass satırı söz dizimi hatası verir
  • D. try bloğu except olmadan da yazılabildiği için gereksizdir
  • E. Programın yavaşlamasına neden olur

Madde 9. Bir traceback çıktısını okurken ilk nereye bakılır?

Traceback (most recent call last):
  File "app.py", line 12, in <module>
    total = calculate(data)
  File "app.py", line 5, in calculate
    return 100 / data["count"]
ZeroDivisionError: division by zero
  • A. En üstteki satıra; hata orada oluşmuştur
  • B. En alttaki satıra; hata türü ve mesajı oradadır
  • C. Satır numaralarının en büyüğüne
  • D. Traceback (most recent call last): satırına
  • E. Dosya adına; hata her zaman o dosyanın ilk satırındadır

Madde 10. Hata ayıklama döngüsünde “tek değişiklik yapın” adımı neden önemlidir?

  • A. Aynı anda birden çok şey değiştirilirse hangi değişikliğin işe yaradığı anlaşılamaz
  • B. Tek değişiklik programı daha hızlı çalıştırır
  • C. Böylece traceback çıktısı kısalır
  • D. Sürüm denetimi yalnızca tek satırlık değişiklikleri kaydeder
  • E. Python aynı anda birden çok satırın değiştirilmesine izin vermez

Madde 1. Doğru: E. with bloğu biterken dosyayı kendisi kapatır; blok içinde istisna yükselse de dosya kapanır. close() çağrısını unutma riski kalmaz.

  • A yanlış: with dosyayla ilgili işleri üstlendiği için dosyayı da hazırladığı sanılabilir. Ama dosyanın oluşup oluşmayacağını kip belirler; "r" kipinde hata yükselir.
  • B yanlış: with dosya ayarlarını kendisi yönetiyormuş gibi görünebilir. Ama encoding yine açıkça yazılmalıdır.
  • C yanlış: with ile açılan dosya çoğunlukla bir for döngüsüyle okunduğu için bölmeyi with yapıyor sanılabilir. Satırlara ayırmak ayrı bir iştir; for line in file ile yapılır.
  • D yanlış: Daha kısa bir yazımın daha verimli bir okuma getireceği düşünülebilir. Ama with okuma biçimini değiştirmez; yalnızca dosyanın kapanmasını üstlenir.

Madde 2. Doğru: D. "w" kipi yıkıcıdır. Var olan içeriği korumak için "a" kullanılır.

  • A yanlış: "w" var olan dosyayı da uyarı vermeden açar; hata yükselmez.
  • B yanlış: Bu "a" kipinin davranışıdır.
  • C yanlış: Böyle bir kip yoktur; başa ekleme elle yapılır.
  • E yanlış: Salt okuma kipi "r"dir.

Madde 3. Doğru: E. Okuma kipi var olan bir dosya bekler; yoksa hata yükselir.

  • A yanlış: open() ya dosya nesnesi verir ya hata yükseltir.
  • B yanlış: Oluşturma davranışı "w" ve "a" kiplerine aittir.
  • C yanlış: Python boş metin döndürüp devam etmez; dosya yoksa hata yükselir.
  • D yanlış: Bu, erişim izni sorunlarında görülür; burada dosya hiç yoktur.

Madde 4. Doğru: B. Kodlama yazılmazsa işletim sisteminin varsayılanı kullanılır; aynı dosya farklı makinelerde Türkçe karakterlerde farklı okunabilir. Kodlamayı açıkça yazarsanız sonuç makinenin varsayılanına bağlı kalmaz.

  • A yanlış: Kodlama baytlarla ilgili olduğu için boyutu etkilediği düşünülebilir. Boyut içeriğe bağlıdır; amaç karakterlerin doğru okunmasıdır.
  • C yanlış: Fazladan yazılan bir parametrenin bir kazanç getirmesi beklenir; akla ilk gelen kazanç da hızdır. Ama kodlama, hızla ilgili bir ayar değildir.
  • D yanlış: Kodlama bayt düzeyinde bir konu olduğu için ikili dosyalarla ilişkilendirilebilir. Oysa ikili kipte kodlama parametresi kullanılmaz; bu bir metin kipi ayarıdır.
  • E yanlış: Her örnekte yazıldığı için zorunlu bir parametre gibi görünür. Zorunlu değildir; yazılmazsa dosya açılır ve işletim sisteminin varsayılanı kullanılır. Sorun da buradan çıkar.

Madde 5. Doğru: C. Program çalışır ve istisna oluşturmaz ama yanlış sonuç verir. Söz dizimi doğru, satır da sorunsuz çalışır. Hatayı ancak sonucu beklenen değerle karşılaştırınca fark edersiniz; bu yüzden test ve örnek girdi gerekir.

  • A yanlış: Hata program çalışırken fark edildiği için bu sınıf akla gelir. Ama yürütme sırasında istisna yükselmez.
  • B yanlış: Sayının 1.20 gibi bir float ile çarpılması tür karışıklığı gibi görünebilir. Ama işlemdeki türler uyumludur.
  • D yanlış: Hatalı bir satırın yazımında da sorun olduğu düşünülebilir. Ama Python satırı sorunsuz okur.
  • E yanlış: “Kodlama” sözcüğü “kod yazarken yapılan hata” diye okunabilir. Ama burada karakter kodlaması kastedilir; bu satırla ilgisi yoktur.

Madde 6. Doğru: D. print yalnızca ekrana yazar; fonksiyonu çağıran kod bir sorun olduğunu anlamaz ve program yanlış durumla devam eder. raise ise normal akışı keser ve çağırana işlemin tamamlanamadığını bildirir.

  • A yanlış: Traceback birçok ortamda kırmızı göründüğü için fark renkte sanılabilir. Ama fark renkte değil, akıştadır.
  • B yanlış: raise örnekleri çoğunlukla fonksiyon içinde görüldüğü için böyle bir kural sanılabilir. İkisi de her yerde kullanılabilir.
  • C yanlış: İki satır aynı mesajı taşıdığı için fark ancak hızda olabilirmiş gibi görünür. Oysa iki satır programın akışını farklı etkiler.
  • E yanlış: Yakalanmayan istisna programı durdurduğu için bu genelleme kolaydır. Ama uygun bir except bloğu yakalarsa program devam eder.

Madde 7. Doğru: C. raise çalıştığı anda return satırına hiç ulaşılmaz; akış except bloğuna geçer ve as error yakalanan istisnayı error adına bağlar.

  • A yanlış: error yakalanan istisnadır; yazdırılınca mesajı görünür.
  • B yanlış: raise çalıştığı için çıkarma hiç yapılmaz.
  • D yanlış: Yükseltilen istisna ValueErrordır; except ValueError bloğu onu yakalar.
  • E yanlış: İki dal birden çalışmaz; raise fonksiyondan çıkar.

Madde 8. Doğru: A. except Exception çok geniştir ve pass hiçbir iz bırakmaz. Beklenen hataların yanında yanlış yazılmış bir ad ya da uyuşmayan türler de hiçbir mesaj vermeden kaybolur; neyin yanlış gittiğini göremezsiniz.

  • B yanlış: Exception bütün hataların ortak adı olduğu için özel bir tür gibi görünebilir. Ama yakalanabilir; sorun zaten neredeyse her hatayı kapsayan bu türü yakalamaktır.
  • C yanlış: Hiçbir iş yapmayan bir satır C’den gelen birine yabancı görünebilir. Ama pass geçerli bir deyimdir; sorun yazımda değil, kodun yaptığı iştedir.
  • D yanlış: Boş görünen except bloğu, bu kısmın silinebileceği izlenimini verir. Ama try bloğu except ya da finally olmadan yazılamaz; sorun yakalamanın genişliğindedir.
  • E yanlış: try bloğunun ek iş yaptığı düşünülebilir. Ama sorun hız değil, gizlenen hata mesajıdır.

Madde 9. Doğru: B. Traceback ilk çağrıdan başlar ve hatanın oluştuğu yere doğru iner. Hata türü ve mesajı en sondadır; hatanın oluştuğu kod satırı hemen onun üstündedir.

  • A yanlış: Metin yukarıdan aşağı okunduğu için ilk satır önemli görünür. Ama en üst satır, o noktaya nasıl gelindiğini gösteren ilk çağrıdır.
  • C yanlış: Hatanın kodun ilerisinde çıktığı düşünülürse en büyük numara aranır. Ama satır numarasının büyüklüğü bir şey söylemez; satırlar çağrıların sırasıyla dizilir.
  • D yanlış: Çıktının en belirgin satırı olduğu için göz önce ona gider. Ama bu yalnızca başlık satırıdır; hatayla ilgili bilgi vermez.
  • E yanlış: C derleyicisinin hata mesajları dosya adıyla başladığı için göz önce ona gidebilir. Ama hatanın hangi satırda olduğu çıktıda line 5 gibi yazılıdır; ilk satırda olması gerekmez.

Madde 10. Doğru: A. Her seferinde tek bir şeyi değiştirirseniz hatayı hangi değişikliğin giderdiğini bilirsiniz. Birkaç şeyi birden değiştirirseniz hata, nedeni anlaşılmadan kaybolabilir ve sonra yeniden ortaya çıkabilir.

  • B yanlış: Başarımla ilgisi yoktur.
  • C yanlış: Traceback uzunluğu çağrı zincirine bağlıdır.
  • D yanlış: Böyle bir sınır yoktur.
  • E yanlış: Böyle bir kısıt yoktur; bu adım Python’la değil, hata arama yöntemiyle ilgilidir.

Tek sayfa özet

  • with open(...) bloğu bitince dosya kapanır, blok içinde istisna oluşsa bile.
  • Türkçe karakterli metinler her makinede aynı okunsun diye kodlamayı açıkça encoding="utf-8" diye yazın.
  • Dosya satırlarını for line in file ile dolaşın. Her satır \n ile biter, önce strip() ile temizleyin.
  • "w" var olan dosyanın içeriğini siler, "a" sonuna ekler.
  • Yalnızca beklediğiniz istisna türünü yakalayın, gerekirse ayrıntısına as error ile bakın. except Exception: pass hataları iz bırakmadan gizler.
  • raise normal akışı keser ve geçersiz durumu fonksiyonu çağıran koda bildirir. C’deki -1 dönüşünün tersine, yakalanmayan istisna gözden kaçmaz.
  • Kodun çalışması, doğru olduğunu göstermez. Mantık hatası istisna oluşturmaz. Beklenen sonucu assert ile yazarsanız yanlış sonuç AssertionError verir.
  • Traceback’i en alttan okuyun: önce hata türü ve mesajı, sonra hatanın oluştuğu satır.
  • Hata mesajını kanıt gibi okuyun, kodu rastgele değiştirmeyin. Her denemede tek bir şeyi değiştirin.
  • Gelecek haftadan itibaren “stok eksiye düşemez” gibi kuralları nesnelerin içinde raise ile koruyacağız.

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

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

  • with open(...) kalıbını kullanır ve dosyanın blok bitiminde kapandığını bilir.
  • "r", "w" ve "a" kiplerini ayırır ve "w" kipinin eski içeriği sildiğini bilir.
  • Metin dosyalarında encoding="utf-8" yazmanın gerekçesini açıklar.
  • Söz dizimi, çalışma zamanı ve mantık hatalarını birbirinden ayırır.
  • raise ile print farkını gösterir ve programın kuralı bozulduğunda istisna yükseltir.
  • Belirli bir istisna türünü yakalar ve istisnayı yakalayıp hiçbir şey yapmamanın neden zararlı olduğunu açıklar.
  • Traceback çıktısını hata türünden başlayarak okur.
Back to top