Dosyalar, istisnalar ve sistematik hata ayıklama
Gerçek programlar yalnızca doğru girdilerle çalışmaz. Dosya bulunmayabilir, kullanıcı sayı yerine metin girebilir, kayıt eksik olabilir veya program mantıksal olarak yanlış sonuç üretebilir. Bu hafta temel dosya işlemlerini ve istisnaları kullanacak; hata mesajını rastgele değişiklik yapma nedeni değil, teşhis kanıtı olarak okuyacağız.
Bu bölümün kapsamı
with open(...)kalıbı ve dosyanın blok bitiminde kapanması"r","w"ve"a"kipleri;"w"kipinin yıkıcılığı- metin dosyalarında
encoding="utf-8"gerekçesi - söz dizimi, çalışma zamanı ve mantık hatalarının ayrımı
raiseileprintfarkı- belirli istisna türünü yakalama ve sessiz yutmanın zararı
- traceback çıktısını hata türünden başlayarak okuma
pathlibve ikili dosya kipleriloggingmodülü- kendi istisna sınıfını tanımlama (12. bölümün konusu)
Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.
Hata oluştuğunda programın ne yapmasını istiyoruz?
Bir hatayı ekrana yazmak, yakalayıp yutmak ve çağırana bildirmek üç ayrı karardır. Üçü de kod olarak birkaç satır tutar; aradaki fark, sorun çıktığında programın kime ne söylediğidir.
Dosyayı güvenli biçimde açmak
with open("notes.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)with bloğu tamamlandığında dosya kapatılır. Elle close() çağrısını unutma riski azalır.
Dosya modları: r, w, a
| Mod | Anlam | Kritik davranış |
|---|---|---|
"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 |
"w" modu yıkıcıdır
with open("odev.txt", "w", encoding="utf-8") as file:
file.write("Yeni içerik")odev.txt zaten varsa eski içerik korunmaz. Var olan dosyaya ekleme yapmak istiyorsanız "a" kullanın. Dosya modunu yazmadan önce “mevcut içeriği korumalı mıyım?” sorusunu sorun.
Web/Pyodide ortamında sanal dosya sistemi kullanılabildiği için küçük dosya deneylerini doğrudan yapabiliriz:
Neden encoding="utf-8" yazıyoruz?
Metin dosyası baytlardan oluşur; karakterlerin bu baytlara nasıl çevrileceğini bir karakter kodlaması belirler. İşletim sisteminin varsayılan kodlamasına güvenmek, özellikle Windows’ta ve Türkçe ç, ğ, ı, İ, ö, ş, ü karakterlerinde farklı makinelerde farklı sonuç üretebilir.
Bu ders boyunca metin dosyalarında açıkça:
encoding="utf-8"kullanacağız. Böylece dosyanın hangi kodlamayla okunup yazıldığı makine varsayımına bırakılmaz.
Satır satır okuma
Büyük veya satır-temelli dosyalarda bütün dosyayı read() ile belleğe almak zorunda değiliz. Dosya nesnesi doğrudan dolaşılabilir:
Bu derste for line in file temel yaklaşımımızdır. readlines() bütün satırları listeye yükler; küçük dosyalarda çalışır ama çoğu satır-temelli işlem için gerekli değildir.
Üç hata sınıfını ayırın
Söz dizimi hatası
if score > 50
print("Geçti")Python kodun yapısını okuyamaz.
Çalışma zamanı hatası
score = int("seksen")Kod okunur, ancak yürütme sırasında sorun oluşur.
Mantık hatası
# Yüzde 20 indirim yapmak isterken:
final = price * 1.20Program çalışır fakat yanlış sonuç üretir. Mantık hataları çoğu zaman istisna üretmediği için test ve örnek girdiyle doğrulama gerektirir.
Hata üretmek: raise
Bazı hatalar Python tarafından kendiliğinden oluşur (int("abc") → ValueError). Bazı geçersiz durumları ise bizim iş kuralımız belirler. Bu durumda raise ile açıkça istisna üretiriz:
raise ValueError(...) çalıştığı anda normal akış kesilir ve uygun except bloğu aranır. raise ile print("hata") aynı şey değildir: print yalnızca mesaj yazar; raise çağırana işlemin normal biçimde tamamlanamadığını bildirir.
Bu mekanizma 6–12. haftalarda nesnelerin invariant’larını ve alan kurallarını korumak için temel araç olacaktır.
try / except: hatayı saklamak için değil yönetmek için
as error, yakalanan istisna nesnesine erişmemizi sağlar; böylece hata mesajını veya ayrıntısını gerektiğinde kullanabiliriz.
except Exception: yazarak her şeyi yakalamak başlangıçta rahat görünebilir; ancak programlama hatalarını da saklayabilir. Beklediğiniz hata türünü mümkün olduğunca açık yazın.
try:
risky_operation()
except Exception:
passbu biçim, neyin yanlış gittiğini görünmez hâle getirir. Öğrenme aşamasında hata mesajını görmek çoğu zaman daha değerlidir.
else ve finally
Tam sözdizimi şu parçaları içerebilir:
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,trybloğu istisnasız tamamlanırsa çalışır.finally, istisna oluşsa da oluşmasa da çalışır; kaynak temizleme gibi “her durumda yapılması gereken” işler için kullanılır.
Dosya açma/kapamada çoğu zaman with kullandığımız için elle finally ile close() yazmamıza gerek kalmaz. Yine de finally kavramını tanımak önemlidir.
Hata iz dökümü (traceback) nasıl okunur?
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 nasıl gelindiğini gösterir.
Hata ayıklama döngüsü
- Yeniden üret: Hata hangi girdide kesin oluşuyor?
- Daralt: En küçük hangi kod parçası hâlâ hatayı üretiyor?
- Kanıt topla: traceback,
print,type, ara değerler. - Hipotez kur: Sorunun nedeni ne olabilir?
- Tek değişiklik yap: Birden çok rastgele değişiklik yapma.
- Yeniden doğrula: Hata gitti mi? Başka durum bozuldu mu?
Bu süreç Nesne II dersinde debugger, logging ve testlerle daha sistematik hâle gelecektir.
Alıştırma — Doğru hata türünü yakala
except ValueError as error:Alıştırma — Kendi hatanı üret
Aşağıdaki fonksiyonu tamamlayın. score 0–100 dışında ise ValueError üretmeli; geçerliyse değeri döndürmelidir:
-1, 0, 100, 101 sınırlarını ayrı ayrı deneyin.
Alıştırma — Mantık hatasını bul
Program hatasız çalışıyor. Ancak yüzde 20 indirim için beklenen sonuç 80 olmalı. Hatanın neden istisna üretmediğini açıklayın ve fonksiyonu düzeltin.
Alıştırma — Dosya verisini doğrula
Kodu önce okuyun; hangi satırın atlanacağını tahmin edin. Daha sonra bozuk satırın yerine 30 yazarak tekrar çalıştırın.
Küçük üretim görevi — 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:
- Dosyayı
encoding="utf-8"ile açsın, for line in fileile dolaşsın,- Geçerli kayıtları listeye eklesin,
- Geçersiz satırı
except ValueError as errorile açık mesajla bildirsin, - Geçerli puanların ortalamasını yazsın,
- Hiç geçerli kayıt yoksa sıfıra bölme hatasına düşmesin,
- Sonuç raporunu ayrı bir dosyaya yazarken
"w"modunun eski içeriği sileceğini bilinçli olarak kullansın.
Çalışır kod teslimi: Normal dosya, bir bozuk satırlı dosya ve hiç geçerli kayıt içermeyen dosya olmak üzere üç senaryoyu çalıştırın. Her senaryoda program kontrollü biçimde tamamlanmalıdır.
Python köprüsünün kapanışı
İlk beş haftada Python’ın temel araçlarını hızlı biçimde kurduk. Bundan sonra dersin odağı değişiyor. Artık soru “Python’da döngü nasıl yazılır?” değil, “Bir problem alanındaki durumu ve davranışı hangi nesne üstlenmeli?” olacaktır.
Elimizde şu beceriler var:
- Değer ve türlerle çalışma,
- Kontrol akışı,
- Koleksiyonlar ve referans sezgisi,
- Fonksiyonla sorumluluk ayırma,
- Modül, dosya ve hata yönetimi,
- Geçersiz durumu
raiseile çağırana bildirme.
Bunların tamamı OOP’nin ham malzemesidir.
Tek sayfa özet
- Hata mesajı bir kanıttır; rastgele değişiklik çağrısı değildir.
raise, geçersiz durumu normal akıştan ayırıp çağırana bildirir.- Beklenen istisnayı dar biçimde yakalayın ve gerektiğinde
as errorile ayrıntısını kullanın. "w"mevcut dosyayı sıfırlar;"a"sona ekler.- Türkçe dâhil taşınabilir metin işlemleri için kodlamayı açıkça
utf-8seçin. - Dosya satırlarını çoğu zaman doğrudan
for line in fileile dolaşabilirsiniz. - Çalışan kod doğru kod olmak zorunda değildir.
- Gelecek haftadan itibaren bu kuralları nesnelerin içinde korumayı öğreneceğiz.
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 yıkıcı olduğunu belirler.- 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.
raiseileprintfarkını gösterir ve iş kuralı bozulduğunda istisna yükseltir.- Belirli bir istisna türünü yakalar ve sessiz yutmanın neden zararlı olduğunu açıklar.
- Traceback çıktısını hata türünden başlayarak okur.