Dosyalar ve basit CSV

Şimdiye kadar verilerimizi doğrudan Python kodunun içine yazdık. Program kapandığında veya kod değiştirildiğinde bu değerlerin kalıcı bir kaynağı yoktu. Gerçek uygulamalarda veriler çoğu zaman dosyalardan okunur ve sonuçlar dosyalara yazılır.

Bu hafta metin dosyalarını açmayı, okumayı ve yazmayı; ardından satır ve sütunlardan oluşan basit CSV verilerini işlemeyi öğreneceğiz. Tarayıcıdaki interaktif örneklerde gerçek bilgisayar dosya sistemine erişmek yerine aynı mantığı güvenli biçimde taklit eden bellek içi metinler kullanacağız. Normal Python ortamında kullanılacak gerçek dosya kodunu ayrıca göreceğiz.

Bu hafta neleri yapabilmelisiniz?

Bölümün sonunda:

  • with open(...) yapısının temel amacını açıklayabilmeli,
  • metin dosyasını okuma ve yazma kiplerini ayırt edebilmeli,
  • encoding="utf-8" kullanımının neden önemli olduğunu açıklayabilmeli,
  • dosya içeriğini satır satır işleyebilmeli,
  • dosya yollarının çalışma dizinine göre yorumlandığını açıklayabilmeli,
  • csv modülüyle basit CSV satırlarını okuyabilmeli,
  • csv.DictReader ile sütun adlarını anahtar olarak kullanabilmeli,
  • sayısal alanlarda gerekli tür dönüşümünü yapabilmeli,
  • küçük bir CSV veri kümesinden toplam veya filtrelenmiş sonuç üretebilmelisiniz.

Dosya neden gerekir?

Bir programın şu verilerle çalıştığını düşünelim:

puanlar = [70, 82, 91, 65]

Bu liste kodun parçasıdır. Oysa puanların başka bir program tarafından üretilmesi veya kullanıcı tarafından daha önce kaydedilmiş olması mümkündür. Böyle bir durumda veri bir dosyada tutulabilir.

Örneğin puanlar.txt:

70
82
91
65

Program bu dosyayı okuyup veriyi işleyebilir.

with open(...) ile dosya açmak

Bir metin dosyasını okumak için temel kalıp:

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    icerik = dosya.read()

print(icerik)

Burada:

  • "puanlar.txt" dosya yoludur,
  • "r" okuma kipidir,
  • encoding="utf-8" karakterlerin nasıl çözüleceğini belirtir,
  • as dosya açılan dosya nesnesine verdiğimiz addır.

with bloğu bittiğinde dosya otomatik olarak kapatılır.

Important

Başlangıç düzeyinde dosya açarken with open(...) kalıbını varsayılan yaklaşım olarak kullanacağız. Dosyayı elle açıp kapatmayı gerektiren yapıları tercih etmeyeceğiz.

Okuma ve yazma kipleri

Sık kullanılan iki temel kip:

Kip Anlam
"r" Dosyayı okumak
"w" Dosyaya yazmak; mevcut içeriği yeniden oluşturmak

Örnek yazma:

with open("sonuc.txt", "w", encoding="utf-8") as dosya:
    dosya.write("İşlem tamamlandı\n")

"w" kipi mevcut dosya içeriğini silebilir ve yeni içerik yazar. Bu nedenle hangi dosyaya yazdığımızı bilmek önemlidir.

Dosya yolu ve çalışma dizini

Şu kod:

open("veriler/puanlar.txt", "r", encoding="utf-8")

dosyanın işletim sistemindeki rastgele bir konumunu değil, programın çalışma dizinine göre veriler/puanlar.txt yolunu arar.

Dosya bulunamazsa FileNotFoundError oluşabilir.

Bu hafta dosya yolu sorunlarını ayrıntılı işletim sistemi düzeyinde ele almıyoruz. Ancak hata ayıklarken şu iki soruyu sormak önemlidir:

Program hangi dizinden çalışıyor?
Dosya yolu o dizine göre doğru mu?

Satır satır okumak

Dosyayı satır satır işlemek için:

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    for satir in dosya:
        print(satir)

Dosya satırları çoğunlukla satır sonu karakteri içerir. Gereksiz boşlukları temizlemek için strip() kullanılabilir:

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    for satir in dosya:
        temiz = satir.strip()
        print(temiz)

Sayısal veri gerekiyorsa dönüşüm yapılır:

puan = int(temiz)

Tarayıcı alıştırmalarında dosya mantığını simüle etmek

Quarto Live tarayıcıda çalıştığı için öğrencinin bilgisayarındaki puanlar.txt dosyasına doğrudan erişmesini beklemiyoruz. Bunun yerine bir metni dosya gibi kullanabiliriz:

StringIO, metni bellek içinde dosya benzeri bir nesne olarak kullanır. Buradaki amaç yeni bir konu öğretmek değildir; gerçek dosya okuma mantığını tarayıcı içinde deneyebilmektir.

Note

Gerçek Python uygulamasında StringIO yerine çoğunlukla with open(...) kullanılacaktır. İnteraktif kitapta tarayıcı kısıtı nedeniyle veri önceden hücreye verilmektedir.

Alıştırma — satırlardaki sayıları toplayın

Aşağıdaki bellek içi dosyada günlük ziyaret sayıları bulunmaktadır.

Beklenen sonuç 500dür.

Döngü içinde deger = int(satir.strip()) ve ardından toplam = toplam + deger kullanabilirsiniz.

from io import StringIO

veri = """120
145
98
137
"""

dosya = StringIO(veri)
toplam = 0

for satir in dosya:
    deger = int(satir.strip())
    toplam = toplam + deger

print(toplam)

CSV nedir?

CSV, tablo biçimindeki verileri düz metin olarak saklamanın yaygın yollarından biridir. Adı “comma-separated values” ifadesinden gelir; ancak ayraç her zaman virgül olmak zorunda değildir.

Basit örnek:

ad,puan,bolum
Deniz,78,Bilgisayar
Ayse,92,Siber
Mert,55,Bilgisayar

İlk satır sütun adlarını, sonraki satırlar kayıtları temsil eder.

CSV verisini split(",") ile elle parçalamak bazı basit örneklerde çalışabilir; fakat tırnak içinde virgül gibi durumlarda hatalı olur. Bu nedenle Python’ın standart csv modülünü kullanacağız.

csv.reader

import csv

with open("ogrenciler.csv", "r", encoding="utf-8", newline="") as dosya:
    okuyucu = csv.reader(dosya)

    for satir in okuyucu:
        print(satir)

Her CSV satırı liste olarak gelir.

İlk satır başlıksa onu ayrıca ele almak gerekir. Başlık adlarını doğrudan anahtar olarak kullanmak için DictReader daha uygundur.

csv.DictReader

import csv

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

    for kayit in okuyucu:
        print(kayit["ad"], kayit["puan"])

Her kayit sözlük benzeri bir yapı olarak okunur.

Önemli ayrıntı: CSV’den gelen değerler başlangıçta metindir.

puan = int(kayit["puan"])

dönüşümü bu nedenle gerekir.

Bir CSV satırının alan adlarıyla sözlük kaydına dönüştürülmesini ve sayısal alan için tür dönüşümü yapılmasını gösteren şema.

Tarayıcıda CSV okuma

Aynı DictReader mantığını StringIO ile deneyebiliriz:

Bu kodda CSV sütunları anlamlı anahtarlarla kullanılmaktadır.

Tür dönüşümünü unutmak

CSV’deki "90" ve "100" değerleri string olarak okunursa sayısal karşılaştırma beklediğimiz gibi çalışmayabilir.

Doğru yaklaşım:

puan = int(kayit["puan"])

if puan >= 60:
    ...

Dönüşümü veriyi okuduğumuz noktaya yakın yapmak, sonraki kodun hangi türle çalıştığını daha açık hâle getirir.

Alıştırma — geçen öğrencileri sayın

Aşağıdaki CSV verisinde puanı 60 veya üzeri olan öğrencilerin sayısını bulun.

Beklenen sonuç 3tür.

puan = int(kayit["puan"]) ile başlayın.

import csv
from io import StringIO

veri = """ad,puan
Deniz,78
Ayse,92
Mert,55
Ece,60
"""

dosya = StringIO(veri)
okuyucu = csv.DictReader(dosya)
gecen_sayisi = 0

for kayit in okuyucu:
    puan = int(kayit["puan"])
    if puan >= 60:
        gecen_sayisi = gecen_sayisi + 1

print(gecen_sayisi)

CSV’den sözlük listesi üretmek

Dosyayı bir kez okuyup program içinde kayıt listesine dönüştürebiliriz:

import csv

ogrenciler = []

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

    for kayit in okuyucu:
        ogrenci = {
            "ad": kayit["ad"],
            "puan": int(kayit["puan"]),
            "bolum": kayit["bolum"]
        }
        ogrenciler.append(ogrenci)

Bu noktadan sonra 11. haftadaki liste ve sözlük işleme fonksiyonlarımız yeniden kullanılabilir.

Bu tasarım önemli bir ayrım kurar:

dosyadan okuma
    ↓
türleri dönüştürme
    ↓
program içi veri yapısı
    ↓
hesaplama / filtreleme / raporlama

Dosya ayrıntılarını her hesaplama fonksiyonunun içine taşımak zorunda değiliz.

Dosyadan satırları okuma, tür dönüşümü, filtreleme veya özetleme ve rapor üretme aşamalarından oluşan CSV veri işleme akışı.

Dosyaya yazmak

Basit bir raporu dosyaya yazalım:

toplam = 450

with open("rapor.txt", "w", encoding="utf-8") as dosya:
    dosya.write(f"Toplam satış: {toplam} TL\n")

Birden fazla satır:

with open("rapor.txt", "w", encoding="utf-8") as dosya:
    dosya.write("Satış Raporu\n")
    dosya.write(f"Toplam: {toplam}\n")

Bu hafta karmaşık CSV yazma seçeneklerine girmiyoruz. Temel hedef veri okuma, tür dönüştürme ve küçük rapor üretme akışını kavramaktır.

Dosya kaynaklı hata durumları

Dosya işlemlerinde hata yalnızca Python sözdiziminden kaynaklanmaz.

Örnekler:

  • dosya bulunamıyor,
  • dosya yolu yanlış,
  • beklenen sütun yok,
  • "puan" alanı sayı değil,
  • dosya boş,
  • karakter kodlaması beklenenden farklı.

Bu sorunları 13. haftada istisnalar ve sistematik hata ayıklama ile daha ayrıntılı ele alacağız.

Üret — CSV satış özeti

Aşağıdaki CSV verisinde ürün ve satış tutarları bulunmaktadır.

csv_satis_ozeti(veri) adlı fonksiyon:

  • CSV metnini DictReader ile okumalı,
  • "tutar" alanını float değerine dönüştürmeli,
  • toplam satış tutarını hesaplamalı,
  • 100 TL ve üzeri kayıtların sayısını bulmalı,
  • (toplam, yuksek_satis_sayisi) demeti döndürmelidir.

Beklenen:

(545.0, 2)

Fonksiyon içinde dosya = StringIO(veri) ve okuyucu = csv.DictReader(dosya) oluşturun. Her kayıtta tutar = float(kayit["tutar"]) kullanın.

import csv
from io import StringIO

def csv_satis_ozeti(veri):
    dosya = StringIO(veri)
    okuyucu = csv.DictReader(dosya)

    toplam = 0
    yuksek_satis_sayisi = 0

    for kayit in okuyucu:
        tutar = float(kayit["tutar"])
        toplam = toplam + tutar

        if tutar >= 100:
            yuksek_satis_sayisi = yuksek_satis_sayisi + 1

    return toplam, yuksek_satis_sayisi

veri = """urun,tutar
Kalem,80
Defter,140
Silgi,25
Canta,300
"""

print(csv_satis_ozeti(veri))

Gerçek ortam uygulaması

Tarayıcı hücresinden farklı olarak kendi Python ortamınızda küçük bir dosya deneyi yapın.

puanlar.txt:

70
82
91
65

Python programı:

toplam = 0
adet = 0

with open("puanlar.txt", "r", encoding="utf-8") as dosya:
    for satir in dosya:
        puan = int(satir.strip())
        toplam = toplam + puan
        adet = adet + 1

print("Ortalama:", toplam / adet)

Dosyayı ve Python programını aynı dizinde tutarak çalıştırın. Daha sonra dosyadaki bir puanı değiştirin ve program koduna dokunmadan sonucu yeniden gözlemleyin.

Bölüm özeti

Bu hafta verinin program kodunun dışında tutulabileceği bir yapıya geçtik.

  • with open(...) dosyayı güvenli biçimde açıp blok sonunda kapatır.
  • "r" okuma, "w" yazma için kullanılan temel kiplerdir.
  • encoding="utf-8" Türkçe karakterler dahil metnin doğru çözümlenmesine yardım eder.
  • Dosya yolları çalışma dizinine göre yorumlanabilir.
  • Satırlar strip() ile temizlenip gerektiğinde int() veya float() ile dönüştürülebilir.
  • CSV tablo benzeri metin verisidir.
  • csv.DictReader sütun adlarını anahtar olarak kullanır.
  • CSV alanları başlangıçta string olarak gelir; sayısal işlemden önce dönüşüm gerekir.
  • Dosya okuma, tür dönüştürme ve hesaplama adımlarını ayırmak kodu daha anlaşılır kılar.
  • Tarayıcı alıştırmalarında gerçek yerel dosya yerine StringIO ile aynı işlem modeli denenebilir.

Kendinizi kontrol edin

  1. with open(...) kullanımının temel avantajı nedir?
  2. "r" ile "w" kipleri arasındaki fark nedir?
  3. encoding="utf-8" neden kullanılır?
  4. Dosya yolu hangi nedenle doğru görünmesine rağmen FileNotFoundError üretebilir?
  5. Satır sonundaki gereksiz karakterleri temizlemek için hangi string metodu kullanılabilir?
  6. csv.DictReader neden düz csv.reader kullanımından bazı kayıt problemlerinde daha okunabilir olabilir?
  7. CSV’den gelen "78" değeri neden doğrudan sayısal puan olarak düşünülmemelidir?
  8. İnteraktif kitapta StringIO kullanmamızın nedeni nedir?

Bir sonraki bölümde dosya ve dönüşüm hataları dahil olmak üzere istisnaları, modülleri ve sistematik hata ayıklamayı ele alacağız.

Back to top