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. Örneklerin çoğu yine not programından. Notlar artık notes.txt dosyasında duruyor, her satırda bir öğrencinin adı ve puanı var: Ayşe,80. 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ı

NotSı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.

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 Python 3.14 ve önceki sürümler 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. Örneğin UTF-8 ile yazılmış Çağlar adı, Türkçe Windows’un kodlamasıyla (cp1254) okununca ÇaÄŸlar olur. Python 3.15’te varsayılan UTF-8 oldu.

Bu ders boyunca metin dosyalarında kodlamayı yine de açıkça encoding="utf-8" diye yazacağız. Kodunuz başka bir bilgisayarda eski bir Python sürümüyle de çalıştırılabilir. Kodlama yazılınca dosyanın hangi kodlamayla okunup yazılacağı ne makineye ne de Python sürümüne bağlı kalır.

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
Uyarı"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.

UyarıHatayı 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. Satırın altındaki ~ ve ^ işaretleri hatanın satırdaki yerini gösterir: burada bölme işlemi. 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.

C ile Python yan yana

Bu haftaki işlerin C’deki ve Python’daki karşılıkları:

İş 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 dosyada mesaj vermek, bozuk satırı atlamak 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
Geçerli not yoksa bunu çağırana bildirmek -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

İlk iki satırda C bilginiz neredeyse olduğu gibi işe yarar, kip harfleri bile aynı. Fark eksik dosyada, bozuk satırda ve hesaplanamayan ortalamada çıkar. 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 soruları da bu mantıkla yazılır.

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

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

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

4. rapor.txt dosyasını bir bilgisayardaki program yazıyor, başka bir bilgisayardaki program okuyor:

# Yazan program
with open("rapor.txt", "w") as file:
    file.write("Öğrenci: Şule Çağlar\n")

# Okuyan program
with open("rapor.txt", encoding="utf-8") as file:
    print(file.read())

İki makinenin ayarları ve Python sürümleri ne olursa olsun Türkçe harflerin doğru okunması için hangi değişiklik yapılmalıdır?

  • A. Okuyan programdaki open() çağrısına "r" kipini yazmak
  • B. Yazan programdaki open() çağrısına da encoding="utf-8" eklemek
  • C. Okuyan programdaki encoding="utf-8" kısmını silmek
  • D. Okuyan programda read() yerine for line in file: kullanmak
  • E. Yazan programda "w" yerine "a" kipini kullanmak

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. Girinti hatası

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

  • A. raise mesajı kırmızı yazar, print düz metin olarak yazar
  • B. raise yalnızca fonksiyon içinde, print her yerde kullanılır
  • C. raise mesajı bir günlük dosyasına, print ekrana yazar
  • D. raise akışı keser ve çağırana bildirir, print yalnız yazar
  • E. raise programı her durumda sonlandırır, print sonlandırmaz

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

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

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

10. Aşağıdaki traceback çıktısından hangi sonuç çıkar?

Traceback (most recent call last):
  File "grades.py", line 12, in <module>
    report(students, scores)
  File "grades.py", line 6, in report
    print(name, average(scores[name]))
KeyError: 'Ece'
  • A. report içindeki 6. satırda sözlükte olmayan 'Ece' anahtarı okundu
  • B. Hata average fonksiyonunun içinde, ortalama hesaplanırken oluştu
  • C. Altıncı satırda söz dizimi hatası var, program hiç başlamadı
  • D. Ece adında bir değişken tanımlanmadığı için program durdu
  • E. Hata 12. satırda, report(students, scores) çağrısının yazımında

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.

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.

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.

4. Doğru: B. Kodlama yazılmazsa yazan program, Python 3.14 ve önceki sürümlerde, kendi işletim sisteminin varsayılanını kullanır. Bu varsayılan, okuyan programın kullandığı UTF-8 olmayabilir. Kodlama iki programda da açıkça yazılınca ikisi aynı kodlamayı kullanır ve sonuç ne makinelerin ayarlarına ne de Python sürümüne bağlı kalır.

  • A yanlış: Kip de open() çağrısının bir ayarı olduğu için çözüm gibi görünebilir. Ama kip yazılmadığında zaten "r" kullanılır; kip baytların hangi karaktere çevrileceğini belirlemez.
  • C yanlış: İki programda da kodlama yazılmayınca ikisi eşitleniyormuş gibi görünür. Ama o zaman her program kendi varsayılanını kullanır. Python 3.14 ve öncesinde bu varsayılan makinenin ayarına bağlıdır ve iki varsayılanın aynı olacağı garanti değildir.
  • D yanlış: Satır satır okumak dosyayı başka biçimde işliyormuş gibi görünebilir. Ama for line in file da baytları aynı kodlamayla karaktere çevirir; kodlama yanlışsa satırlarda da harfler bozuk çıkar.
  • E yanlış: "a" kipi eski içeriği silmediği için daha güvenli görünebilir. Ama kip yalnız yazmanın dosyanın sonuna mı yapılacağını, dosyanın baştan mı yazılacağını belirler; kodlamayı değiştirmez.

5. Doğru: C. Program çalışır ve istisna yükseltmez 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ış: Python’da girinti bloğun parçası olduğu için hatalı satırda girinti sorunu arandığı olur. Ama bu tek satırlık bir atamadır, girintisinde sorun yoktur.

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ış: Hata mesajlarının bir yere kaydedildiği düşünülebilir. Ama raise hiçbir dosyaya yazmaz; istisnayı çağırana iletir, yakalanmazsa mesaj traceback içinde ekranda görünür.
  • E yanlış: Yakalanmayan istisna programı durdurduğu için bu genelleme kolaydır. Ama uygun bir except bloğu yakalarsa program devam eder.

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.

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.

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.

10. Doğru: A. Okumaya en alttan başlanır: hata türü KeyError, yani sözlükte olmayan bir anahtar istenmiş. Hemen üstteki satırlar hatanın report fonksiyonunda, 6. satırda scores[name] okunurken oluştuğunu gösterir.

  • B yanlış: Satırda average çağrısı da geçtiği için hata onun içinde sanılabilir. Ama average çağrılmadan önce argümanı olan scores[name] hesaplanır ve hata bu sırada oluşur. Dökümde average için bir File ... in average satırı yoktur.
  • C yanlış: Söz dizimi hatasında program hiç çalışmaz ve döküm SyntaxError ile biter. Buradaki döküm ise programın çalıştığını ve 12. satırdan report fonksiyonuna girdiğini gösteriyor.
  • D yanlış: 'Ece' bir ad gibi göründüğü için tanımsız değişken hatası sanılabilir. O durumda hata türü NameError olurdu. KeyError sözlükte bulunmayan bir anahtarı bildirir.
  • E yanlış: Döküm 12. satırla başladığı için hata orada sanılabilir. Ama en üstteki satır yalnız ilk çağrıdır; programın report fonksiyonuna o satırdan girdiğini gösterir.

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.
Başa dön