Bütünleştirici mikro uygulama

Bu bölümde yeni bir Python kavramı yok. İlk 13 haftada öğrendiğimiz yapıları küçük ama gerçek hayattan bir problemde birlikte kullanacak, birbirine nasıl bağlandıklarını göreceğiz.

Mikro uygulamamız kampüsteki kırtasiyenin satış raporunu hazırlayacak. Bu kez veri kodun içindeki bir listeden gelmeyecek. Satışları bir CSV dosyasından okuyacağız. Ham kayıtları (dosyadan okunduğu gibi, henüz işlenmemiş satırları) sayıya çevirecek, geçersiz olanları ayıracak, raporu yazdıracak ve önemli davranışları küçük testlerle doğrulayacağız.

Uygulamada şu konular yeniden karşınıza çıkacak:

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
  • Dönemin tamamı; final bu bölümün kapsamıyla sınırlı değildir
  • Kodu modüllere ayırmanın gerekçesi
  • CSV alanlarını güvenli çözme ve geçersiz kaydı ayıklama
  • Türkçe metin normalleştirmesinin gruplamaya etkisi
  • “veri yok” durumunu None ile raporlama
  • Değişiklik sonrası eski doğrulama kontrollerini yeniden çalıştırma
  • AI’ın önerdiği kodu kabul kriterleriyle değerlendirme
  • Örnek uygulamadaki dosya ve fonksiyon adlarını ezberlemek
  • Uygulamaya eklenebilecek ileri özelliklerin tasarımı

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

Problem ve veri dosyası

Kırtasiyede satışlar tezgâhtaki tabletten giriliyor ve kayıtlar satislar.csv dosyasında birikiyor. Kırtasiyenin sahibi gün sonunda bir rapor istiyor: kaç kayıt kullanılabildi, kaç kayıt kullanılamadı, günün cirosu (satışlardan gelen toplam para), her ürünün toplam adedi ve en çok para getiren ürün. Sahibin iki kuralı var. Aynı ürün raporda tek satırda toplanır. Adedi okunamayan ya da sıfır olan kayıt satış sayılmaz, ama kullanılamayan kayıtlar arasında sayılır.

Dosyayı Türkçe ayarlı Excel kaydetmiş, bu yüzden alanlar noktalı virgülle ayrılmış ve ondalık sayılarda virgül kullanılmış. Gözden kaçabilecek bir ayrıntı da var: Kalem adının başında ve sonunda boşluk duruyor.

urun;fiyat;adet
 Kalem ;12,5;3
Defter;45;2
İĞNE;5,5;4
iğne;5,5;2
Silgi;8;abc
Cetvel;10;0

Programın yazdırması gereken özet:

Geçerli kayıt sayısı: 4
Geçersiz kayıt sayısı: 2
Toplam ciro: 160.50 TL
Ürün adetleri: {'kalem': 3, 'defter': 2, 'iğne': 6}
Ciroya en fazla katkı: defter (90.00 TL)
Not

"12,5" ve "5,5" doğrudan float() ile sayıya çevrilemez. Önce ondalık virgülü noktaya çevirmemiz gerekir. Bu örnekteki verinin biçimini biliyoruz: her sayıda yalnızca bir ondalık virgül var. Bu yüzden replace(",", ".") yeterli. 1.234,56 gibi binlik ayracı da içeren sayılarda bu basit yöntem işe yaramaz.

Uygulamanın dosya yapısı

Proje bir veri dosyası ile dört Python dosyasından oluşuyor:

hafta14/
├── satislar.csv
├── veri.py
├── rapor.py
├── main.py
└── test_kontrolleri.py

satislar.csv dosyasından veri.py ve rapor.py modüllerine, oradan main.py ile çıktı raporuna ve test kontrollerine giden akış.

Bütünleştirici mikro uygulamanın akışı

Akış kabaca şöyle:

satislar.csv
    ↓
veri.py: CSV'yi oku
    ↓
rapor.py: temizle → dönüştür → doğrula → özetle
    ↓
main.py: programı çalıştır ve raporu yazdır
    ↓
test_kontrolleri.py: temel davranışları doğrula
İpucu

Kodu dosyalara bölmemizin nedeni, her dosyaya tek bir iş vermektir: veriyi okumak, hesaplamak ve programı başlatmak ayrı işlerdir. Bir sonuç yanlış çıktığında hangi dosyaya bakacağınızı bilirsiniz.

veri.py: CSV kayıtlarını okumak

12. haftada gördüğümüz Excel ve CSV ayrıntıları burada işe yarıyor:

import csv


def kayitlari_oku(dosya_yolu):
    kayitlar = []

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

        for satir in okuyucu:
            kayitlar.append(satir)

    return kayitlar

veri.py sayıları çevirmiyor. CSV’deki alanları olduğu gibi, string olarak okuyor. Çevirme işi rapor.py dosyasına kalıyor.

  • encoding="utf-8-sig", dosyanın başında BOM (Excel’in dosya başına koyduğu görünmez işaret) varsa ilk sütun adının urun olmasını engeller.
  • delimiter=";", noktalı virgülle ayrılmış CSV’yi doğru sütunlara böler.
  • newline="" verildiğinde satır sonlarını csv modülü kendisi işler.

Türkçe ürün adını normalleştirmek

8. haftada .lower() metodunun Türkçe I ve İ harflerinde beklenmedik sonuç verdiğini görmüştük: "I".lower() ı yerine i verir, "İ".lower() ise i harfinin yanına ayrı bir nokta işareti ekler. Aynı sorunu burada ürün adlarında çözüyoruz. urun_adi_temizle() önce boşlukları kırpar, sonra I ve İ harflerini elle dönüştürür, en son .lower() çağırır.

Hücredeki dört satır ne yazar? Son satıra özellikle dikkat edin.

İlk üç satır kalem, iğne ve ısparta yazar. Son satır False yazar: yalnız .lower() kullanılırsa İ iki karaktere dönüşür ve sonuç ekranda iğne gibi görünse de "iğne" ile eşit olmaz.

Böylece İĞNE ile iğne raporun sözlüklerinde iki ayrı anahtar olmaz.

Uyarı

Bu dönüşüm Türkçe metinler için yazıldı. E-posta adresi, kullanıcı adı ya da uluslararası ürün kodu gibi alanlarda aynı dönüşümün doğru sonuç vereceğini varsaymayın.

Sayısal alanları güvenli çözmek

7. bölümde fonksiyonun sözleşmesini görmüştük: fonksiyonun ne beklediğini ve ne döndürdüğünü söyleyen yazılı not. Fiyatı çözen fonksiyonun sözleşmesi şu: metni sayıya çevir, fiyat 0 olabilir ama negatif olamaz, çevrilemeyen ya da negatif değerde None döndür. Fonksiyonun adı da bunu söylesin.

Hücredeki dört satır ne yazar?

Adet ise pozitif bir tam sayı olmalı: sahibin kuralına göre 0 adetli kayıt satış sayılmaz. "3", "0" ve "abc" için bu fonksiyon ne döndürür?

İlk hücre 12.5, 0.0, None ve None yazar. "0" kabul edilir, çünkü fiyat negatif değildir. "-1" sözleşmeye uymadığı, "abc" ise sayıya çevrilemediği için None döner.

İkinci hücre 3, None ve None yazar. "0" bir tam sayıdır ama pozitif değildir. "abc" için int() ValueError verir, except bloğu bunu yakalar ve None döndürür.

Adları bu yüzden dikkatle seçtik. pozitif_sayi_coz adlı bir fonksiyon "0" için 0 döndürseydi, adı bir şey, davranışı başka bir şey söylerdi.

None ve is None

13. haftada None değerini “sonuç elde edilemedi” sinyali olarak kullanmıştık. Burada da aynı kalıp var:

fiyat = negatif_olmayan_sayi_coz("abc")

if fiyat is None:
    print("Fiyat geçersiz")

Python’da tek bir None nesnesi vardır. Bu yüzden None kontrolü şöyle yazılır:

if deger is None:
    ...

Tersi için:

if deger is not None:
    ...
Önemli

Bir fonksiyon geçersiz girdide None döndürüyorsa çağıran kod sonucu kontrol etmek zorundadır. Kontrol etmezse hata daha sonra, örneğin None * 3 gibi nereden geldiği belli olmayan bir satırda çıkabilir.

Bir ham kaydı dönüştürmek

Şimdi CSV’den gelen tek bir ham kaydı, hesapta kullanabileceğimiz bir sözlüğe çevirelim:

def kaydi_coz(kayit):
    urun_metni = kayit.get("urun")
    fiyat_metni = kayit.get("fiyat")
    adet_metni = kayit.get("adet")

    if urun_metni is None or fiyat_metni is None or adet_metni is None:
        return None

    urun = urun_adi_temizle(urun_metni)
    fiyat = negatif_olmayan_sayi_coz(fiyat_metni)
    adet = pozitif_tam_sayi_coz(adet_metni)

    if urun == "" or fiyat is None or adet is None:
        return None

    return {
        "urun": urun,
        "fiyat": fiyat,
        "adet": adet
    }

Fonksiyon üç şeyi denetliyor:

  • Beklenen sütun var mı?
  • Ürün adı boş mu?
  • Sayısal alanlar fonksiyonların sözleşmesine uyuyor mu?

Tahmin et: hangi kayıtlar geçerli?

Aşağıdaki hücre dört örnek kaydı kaydi_coz() ile çözüyor. Çalıştırmadan önce her satırın sözlük mü, None mı olacağını tahmin edin:

İlk iki kayıt sözlüğe dönüşür: {'urun': 'kalem', 'fiyat': 12.5, 'adet': 3} ve {'urun': 'iğne', 'fiyat': 5.5, 'adet': 4}. Ürün adları kırpılmış ve küçültülmüş, fiyatlar float olmuştur. Son iki satır None yazar: Silgi kaydının adedi sayıya çevrilemez, Cetvel kaydının adedi 0 olduğu için pozitif değildir.

Satır toplamı ve ürün başına ciro

Geçerli bir kaydın ciroya katkısı fiyatla adedin çarpımıdır:

def satir_toplami(kayit):
    return kayit["fiyat"] * kayit["adet"]

Her ürünün toplam adedini ve toplam cirosunu ayrı sözlüklerde biriktireceğiz:

urun_adetleri[urun] = urun_adetleri.get(urun, 0) + adet
urun_cirolari[urun] = urun_cirolari.get(urun, 0) + satir_cirosu

Burada 10. ve 11. haftalardaki sözlük biriktirme kalıbını olduğu gibi kullanıyoruz: ürün sözlükte henüz yoksa get(urun, 0) sayımı 0’dan başlatır.

Maksimum arama kalıbını yeniden kullanmak

Ciroya en çok katkı yapan ürünü hazır max() fonksiyonu yerine daha önce öğrendiğimiz maksimum arama kalıbıyla bulalım. Hücre fonksiyonu önce iki ürünlü bir sözlükle, sonra boş bir sözlükle çağırıyor. İki satır ne yazar?

Sözlük boşsa en büyük değerden söz edilemez. Bu yüzden fonksiyon None döndürüyor. 0 döndürseydik “hiç veri yok” durumu, “en yüksek ciro 0” gibi gerçek bir sonuçla karışırdı.

rapor.py: ana rapor fonksiyonu

Parçaları birleştirelim:

def satis_raporu(ham_kayitlar):
    toplam_ciro = 0
    gecerli_sayisi = 0
    gecersiz_sayisi = 0
    urun_adetleri = {}
    urun_cirolari = {}

    for ham_kayit in ham_kayitlar:
        kayit = kaydi_coz(ham_kayit)

        if kayit is None:
            gecersiz_sayisi = gecersiz_sayisi + 1
            continue

        gecerli_sayisi = gecerli_sayisi + 1

        urun = kayit["urun"]
        adet = kayit["adet"]
        satir_cirosu = satir_toplami(kayit)

        toplam_ciro = toplam_ciro + satir_cirosu
        urun_adetleri[urun] = urun_adetleri.get(urun, 0) + adet
        urun_cirolari[urun] = urun_cirolari.get(urun, 0) + satir_cirosu

    return {
        "gecerli": gecerli_sayisi,
        "gecersiz": gecersiz_sayisi,
        "ciro": toplam_ciro,
        "urun_adetleri": urun_adetleri,
        "urun_cirolari": urun_cirolari,
        "lider": en_yuksek_cirolu_urun(urun_cirolari)
    }

Bu fonksiyonda yeni bir söz dizimi yok. Önceki haftalarda gördüğümüz şu kalıplar bir araya geliyor:

  • for ile kayıtları dolaşma
  • None kontrolü
  • continue
  • Sayaç ve biriktirici
  • Sözlükle gruplama
  • Fonksiyon çağrıları
  • Maksimum arama

Tarayıcıda bütün akışı deneyin

Kendi bilgisayarınızda satislar.csv dosyasını open() ile açarsınız. Kod hücresinde ise aynı CSV metnini StringIO ile okuyabiliriz. StringIO, Python’ın io modülündeki bir araçtır: bir metni dosyaymış gibi satır satır okutur.

Hücre bütün akışı çalıştırıp beş satır yazdırıyor. Çıktı, “Problem ve veri dosyası” başlığındaki beklenen özetle aynı mı olur? Hangi satır farklı görünür?

Geçerli kayıt sayısı: 4
Geçersiz kayıt sayısı: 2
Toplam ciro: 160.50 TL
Ürün adetleri: {'kalem': 3, 'defter': 2, 'iğne': 6}
Ciro lideri: ('defter', 90.0)

İlk dört satır beklenen özetle aynıdır. Son satır farklı görünür: en_yuksek_cirolu_urun() bir demet döndürür ve print() onu olduğu gibi yazar. Beklenen biçimi, yani defter (90.00 TL) yazısını main.py demeti açıp f-string ile yazdırarak verir.

main.py: dosya hatasını yakalamak ve raporu yazdırmak

Asıl dosyayı okuyan ana program:

from veri import kayitlari_oku
from rapor import satis_raporu


def main():
    try:
        kayitlar = kayitlari_oku("satislar.csv")
    except FileNotFoundError as hata:
        print("Satış dosyası bulunamadı:", hata)
        return

    rapor = satis_raporu(kayitlar)

    print("Geçerli kayıt sayısı:", rapor["gecerli"])
    print("Geçersiz kayıt sayısı:", rapor["gecersiz"])
    print(f"Toplam ciro: {rapor['ciro']:.2f} TL")
    print("Ürün adetleri:", rapor["urun_adetleri"])

    if rapor["lider"] is not None:
        urun, ciro = rapor["lider"]
        print(f"Ciroya en fazla katkı: {urun} ({ciro:.2f} TL)")


if __name__ == "__main__":
    main()

Burada 13. haftadan iki konu bir arada:

  • Dosyanın bulunamaması önceden beklenen bir durumdur. FileNotFoundError yakalanır ve bir mesaj yazdırılır.
  • Main guard (if __name__ == "__main__": satırı) sayesinde main() yalnız main.py doğrudan çalıştırıldığında çağrılır.

Küçük regresyon kontrolleri

Kod çalışıyor görünse de önemli davranışları assert ile sınayalım. Bu kontroller kodu sonradan değiştirdiğinizde de işe yarar: daha önce doğru çalışan bir davranış bir değişiklikten sonra bozulursa (buna regresyon denir) hemen fark edersiniz.

assert urun_adi_temizle("İĞNE") == "iğne"
assert urun_adi_temizle("iğne") == "iğne"

assert negatif_olmayan_sayi_coz("12,5") == 12.5
assert negatif_olmayan_sayi_coz("0") == 0
assert negatif_olmayan_sayi_coz("-1") is None
assert negatif_olmayan_sayi_coz("abc") is None

assert pozitif_tam_sayi_coz("3") == 3
assert pozitif_tam_sayi_coz("0") is None
assert pozitif_tam_sayi_coz("-2") is None
assert pozitif_tam_sayi_coz("abc") is None

assert kaydi_coz({"urun": " ", "fiyat": "10", "adet": "1"}) is None

rapor = satis_raporu([
    {"urun": "İĞNE", "fiyat": "5,5", "adet": "4"},
    {"urun": "iğne", "fiyat": "5,5", "adet": "2"},
])

assert rapor["gecerli"] == 2
assert rapor["gecersiz"] == 0
assert rapor["urun_adetleri"]["iğne"] == 6
assert abs(rapor["ciro"] - 33.0) < 0.001

Son satırda == yerine küçük bir tolerans (kabul ettiğimiz küçük fark) kullandık. 7. haftada kayan noktalı sayıları sınarken de böyle yapmıştık.

Hata ayıklama senaryosu

Program beklenen 160.50 TL yerine başka bir sonuç verirse bütün kodu aynı anda değiştirmeyin.

Şu sırayı izleyin:

  1. CSV’de kaç satır olduğunu kontrol edin.
  2. kayitlari_oku() sonrasında ilk birkaç ham kaydı inceleyin.
  3. Her ham kayıt için kaydi_coz() sonucunu kontrol edin.
  4. Silgi ve Cetvel kayıtlarının neden geçersiz olduğunu doğrulayın.
  5. İĞNE ve iğne değerlerinin aynı anahtara dönüştüğünü kontrol edin.
  6. Her geçerli kayıt için satir_toplami() sonucunu hesaplayın.
  7. urun_cirolari sözlüğünün her turdaki durumunu izleyin.
  8. Hatanın nedeni hakkında tek bir tahmin seçin ve onu sınayacak küçük bir değişiklik yapın.
  9. Bütün assert kontrollerini yeniden çalıştırın.

Böylece 13. haftada gördüğümüz adım adım hata ayıklama yöntemini gerçek bir veri akışında kullanmış olursunuz.

AI’ın önerdiği kodu sınamak

Bu noktada AI’dan küçük bir değişiklik ya da başka bir çözüm isteyebilirsiniz. Ama verdiği kodu olduğu gibi kabul etmeyin, önce sınayın.

Örneğin AI pozitif_tam_sayi_coz() için aşağıdaki kısa sürümü önerebilir. İlk bakışta makul görünüyor. Hücredeki üç çağrıdan hangisi beklediğimiz sonucu vermez?

İlk satır 3 yazar. İkinci satır 0 yazar, oysa bu uygulamada adet pozitif olmalı: None bekliyorduk. Üçüncü çağrı ValueError verir ve program orada durur. Sözleşmemiz geçersiz girdide None döndürmeyi istiyordu.

Bu iki sorunu kabul kriterlerimiz yakaladı. Kabul kriteri, bir davranışın doğru sayılması için sağlanması gereken, denenebilir bir koşuldur: “"0" için None döner”, “"abc" için hata vermeden None döner” gibi.

AI’ın önerdiği kodu değerlendirirken şu üç soruyu sorun:

  1. Sözleşmeye uyuyor mu?
  2. Sınır ve geçersiz durum testlerini geçiyor mu?
  3. Daha önce doğru çalışan bir davranışı bozuyor mu?
Önemli

AI’ın yazdığı kod daha kısa ya da daha “profesyonel” görünebilir. Bu, doğru olduğunu göstermez. Bu derste bir kodu kabul etmeniz için ne yaptığını açıklayabilmeniz ve doğrulamış olmanız gerekir.

Hepsi bir arada: gün sonu raporu

Kırtasiyenin gün sonu raporunu bölüm boyunca parça parça yazdık. Raporu her akşam elle çıkaran biri de aynı adımları izlerdi. Dört durum bu adımları sınıyor. İĞNE ve iğne iki ayrı kayıtta geliyor. Silgi kaydında adet yerine abc yazıyor. Bir gün hiç satış girilmiyor. Bir arkadaşınız da kodu kısaltmayı öneriyor: “Adedi kontrol etme, sayıya çevir ve fiyatla çarp.”

Aşağıdaki tablo bu dört durumu Türkçe adımıyla ve Python karşılığıyla yan yana koyuyor.

Durum Türkçe adım Python’da Dikkat
İĞNE ve iğne “Ürün adlarını aynı biçime getir, sonra topla” urun_adi_temizle(): strip(), I ve İ dönüşümü, sonra lower() Yalnız .lower() yazılırsa İĞNE ile iğne iki ayrı ürün olur
Silgi kaydında abc “Adet okunmuyorsa kaydı kullanılamayanlara say, hesaba katma, sıradakine geç” pozitif_tam_sayi_coz() None döndürür, döngü geçersiz sayacını artırıp continue ile sıradaki kayda geçer try olmadan int("abc") ValueError verir ve rapor hiç çıkmaz. 0 kontrolü olmazsa Cetvel de satış sayılır
Hiç satış yok “Satış yoksa ‘yok’ yaz” en_yuksek_cirolu_urun() None döndürür, main() is not None ile bakar 0 döndürülürse “satış yok” ile “en yüksek ciro 0 TL” karışır
Arkadaşın önerisi “Kabul etmeden önce eski durumlarla dene” test_kontrolleri.py içindeki assert satırları yeniden çalıştırılır Önerilen kod "0"’ı kabul eder ve "abc" için hata verir. Bu iki davranışı sınayan assert satırları başarısız olur

Adedi fiyatla çarpmadan önce okunup okunmadığına bakan bir adım yoksa Python da bakmaz: int("abc") bütün raporu durdurur. Boş gün için de ayrı bir adım gerekir, yoksa “en çok para getiren ürün” satırına ne yazılacağı belli olmaz. Arkadaşınızın önerisini Silgi ve Cetvel kayıtlarıyla denemek de bir regresyon kontrolüdür.

Uygulamaya tek bir özellik eklemek

Hazır projeye aşağıdakilerden yalnızca birini eklemeyi deneyin:

  • Fiyatı 0 olan kayıtları ayrıca saymak
  • Belirli bir ciro eşiğinin üzerindeki ürünleri listelemek
  • Raporu rapor.txt dosyasına yazmak
  • Geçersiz kayıtların nedenlerini ayrı sayaçlarda toplamak
  • Aynı ürün farklı fiyatlarla gelirse rapora uyarı eklemek

Her özellik bir gereksinimdir, yani programdan istenen yeni bir davranış. Aşağıdaki şema, bir gereksinimin kabul kriterine, koda ve teste nasıl dönüştüğünü gösteriyor.

Gereksinim, kabul kriteri, kod değişikliği ve test arasındaki doğrulama zinciri.

Gereksinimden teste

Özellik eklemeden önce kabul kriterini yazın. Sonra şu anki kodun bu kriteri karşılamadığı en az bir örnek hazırlayın.

Örneğin:

Aynı ürün iki farklı fiyatla gelirse rapor bu ürünü "fiyat tutarsızlığı" olarak işaretlemeli.

Bu kriteri sınayacak veri:

[
    {"urun": "Kalem", "fiyat": "10", "adet": "1"},
    {"urun": "Kalem", "fiyat": "12", "adet": "1"},
]

Kodu ancak bundan sonra değiştirin. Değiştirdikten sonra eski kontrolleri de yeniden çalıştırın.

Yerel çalışma dosyaları

Örneği kendi bilgisayarınızda çalıştırmak için bütün dosyaları buradan indirip aynı klasöre kaydedin:

Windows’ta klasörü Dosya Gezgini’nde açın, adres çubuğuna cmd yazıp Enter’a basın. Komut istemi o klasörde açılır. Önce testleri çalıştırın:

python test_kontrolleri.py

Kontrollerin hepsi geçerse ekranda Bütün kontroller geçti. yazısı görünür. Ardından programı çalıştırın:

python main.py

Kurulumunuza göre python yerine py yazmanız gerekebilir.

Ders sonu kontrolü

Mikro uygulama için şu sorulara cevap verebilmelisiniz:

  1. satislar.csv verisi neden okunduğu gibi hesapta kullanılmıyor?
  2. utf-8-sig ve delimiter=";" hangi gerçek dosya sorunlarını çözüyor?
  3. urun_adi_temizle() neden yalnızca .lower() kullanmıyor?
  4. negatif_olmayan_sayi_coz() ile pozitif_tam_sayi_coz() sözleşmeleri neden farklıdır?
  5. None burada ne anlama geliyor ve neden is None ile kontrol ediliyor?
  6. 0 adetli satış neden bu uygulamada geçersiz kabul edildi?
  7. urun_adetleri ve urun_cirolari sözlükleri hangi biriktirme kalıbını kullanıyor?
  8. Ciroya en çok katkı yapan ürün nasıl bulunuyor?
  9. FileNotFoundError hangi modülde ve neden yakalanıyor?
  10. AI’ın önerdiği bir değişikliği kabul etmeden önce hangi testleri çalıştırırsınız?

Deneme sınavı: 25 soru

Bu 25 soru, finalin nasıl olacağını birebir gösterir: final de 25 sorudur, her soru beş şıklıdır ve her kazanımdan en fazla bir soru gelir. Önce kendiniz çözün, sonra cevap anahtarındaki gerekçeleri okuyun.

1. Algoritma ile program arasındaki fark nedir?

  • A. Algoritma Python’da, program ise C gibi derlenen dillerde yazılır
  • B. Algoritma çözümün adımlarıdır, program bu adımların çalışan kodudur
  • C. Algoritma programdan kısadır, çünkü ayrıntı içermez
  • D. Algoritma kâğıda yazılır, program ise bilgisayarda yazılır
  • E. Algoritma bir matematik formülüdür, program bu formülü hesaplar

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

a = 10
b = a + 5
a = 20
print(a)
print(b)
  • A. 10 ve 25
  • B. 20 ve 20
  • C. 10 ve 15
  • D. 20 ve 15
  • E. 20 ve 25

3. puan = 45 iken aşağıdaki program ne yazdırır?

if puan >= 50:
    print("Geçti")
else:
    print("Kaldı")
  • A. Önce Geçti, sonra Kaldı
  • B. Geçti
  • C. Hata verir; puan karşılaştırmadan önce dönüştürülmelidir
  • D. Hiçbir şey yazmaz
  • E. Kaldı

4. while döngüsünde koşul ne zaman sınanır?

  • A. Her yinelemeden sonra; gövde en az bir kez çalışır
  • B. Yalnızca döngüye ilk girişte
  • C. Gövdenin ortasında, güncelleme satırından hemen sonra
  • D. Her yinelemeden önce, ilk tur dâhil
  • E. Program başlarken bir kez, sonra sonuç saklanır

5. range(1, 5) hangi değerleri üretir?

  • A. 0, 1, 2, 3, 4
  • B. 1, 2, 3, 4
  • C. 1, 5
  • D. 5, 4, 3, 2, 1
  • E. 1, 2, 3, 4, 5

6. Fonksiyon tanımı ile fonksiyon çağrısı arasındaki fark nedir?

  • A. Tanım fonksiyonu bir kez çalıştırır, çağrı ise tekrar çalıştırır
  • B. Tanım fonksiyonu kaydeder, çağrı onu çalıştırır
  • C. Tanım parantezli, çağrı parantezsiz yazılır
  • D. İkisi aynı şeydir, def yazımı isteğe bağlıdır
  • E. Tanım dosyanın sonunda, çağrı başında yer alır

7. Bir fonksiyonun sözleşmesi hangi üç soruya cevap verir?

  • A. Hangi dosyada yer alır, kim yazmıştır ve ne zaman yazılmıştır
  • B. Ne kadar hızlı çalışır, ne kadar bellek kullanır ve kaç kez çağrılır
  • C. Hangi girdileri kabul eder, ne yapar ve ne döndürür
  • D. Hangi hataları verir, hangi sürümde çalışır ve hangi modülü kullanır
  • E. Kaç satır uzunluktadır, hangi döngüyü kullanır ve kaç değişken tanımlar

8. "Python"[0] ve "Python"[-1] sırasıyla hangi karakterleri verir?

  • A. P ve P
  • B. n ve P
  • C. P ve n
  • D. y ve o
  • E. Hata verir; negatif indeks kullanılamaz

9. [10, 20, 30, 40][1:3] ifadesinin sonucu nedir?

  • A. 20 ve 30 ayrı ayrı
  • B. [20, 30, 40]
  • C. [10, 20, 30]
  • D. [20, 30]
  • E. [10, 20]

10. append() ve remove() sırasıyla ne yapar?

  • A. append() sona ekler, remove() verilen değeri siler
  • B. append() başa ekler, remove() son elemanı siler
  • C. append() listeyi sıralar, remove() listeyi boşaltır
  • D. İkisi de yeni bir liste döndürür
  • E. append() sona ekler, remove() verilen indeksteki elemanı siler

11. urun = {"ad": "Kalem", "fiyat": 15} iken urun["fiyat"] ifadesindeki "fiyat" nedir?

  • A. Sözlüğün adı; sözlüğe bu adla ulaşılır
  • B. Bir metot çağrısı; fiyatı okur
  • C. İndeks; 1 numaralı elemanı gösterir
  • D. Değer; köşeli parantez içindeki veridir
  • E. Anahtar; 15 değerine bu adla ulaşılır

12. kitap = {"baslik": "Sefiller", "sayfa": 512} iken "Sefiller" in kitap sonucu nedir?

  • A. None döner; eşleşen anahtar bulunmaz
  • B. KeyError oluşur; "Sefiller" bir anahtar değil
  • C. "baslik"; eşleşen anahtarı döndürür
  • D. True; Sefiller sözlüğün içindedir
  • E. False; in yalnız anahtarlara bakar

13. ogrenciler bir sözlük listesiyken ogrenciler[2]["puan"] ifadesi ne yapar?

  • A. puan adlı listenin 2 numaralı elemanını verir
  • B. 2 numaralı kaydın puan alanını okur
  • C. Üçüncü kaydı listeden siler
  • D. Listenin 2 numaralı elemanını puan değeriyle değiştirir
  • E. Bütün kayıtların puan alanlarını toplar

14. gecenler.append(ogrenci) satırı neden yeni bir sözlük kopyası oluşturmaz?

  • A. append() aynı sözlüğe bir referans ekler
  • B. append() sayıları kopyalar, sözlükleri kopyalamaz
  • C. gecenler zaten ogrencilerin kopyasıdır
  • D. Python kopyayı döngü bitince oluşturur
  • E. Sözlükler değiştirilemez olduğu için kopyaya gerek yoktur

15. "r", "w" ve "a" kipleri arasındaki fark nedir?

  • A. "r" okur, "w" ile "a" ikisi de sona ekler
  • B. "r" okur; "w" ve "a" dosya yoksa hata verir
  • C. "r" okur, "w" sona ekler, "a" içeriği siler
  • D. "r" okur, "w" baştan yazar, "a" sona ekler
  • E. "r" ve "w" metin, "a" ikili dosyalar içindir

16. read() ile readlines() hangi türde değer döndürür?

  • A. read() satır listesi, readlines() tek bir metin döndürür
  • B. İkisi de satırlardan oluşan bir liste döndürür
  • C. read() sayı, readlines() metin döndürür
  • D. read() tek bir metin, readlines() satır listesi döndürür
  • E. İkisi de dosyanın tamamını tek metin olarak döndürür

17. Söz dizimi hatası, çalışma zamanı hatası ve mantık hatası nasıl ayrılır?

  • A. Üçü de kod çalışırken çıkar; aralarındaki fark yalnızca mesajın metnidir
  • B. Söz dizimi hatası mesaj vermez; çalışma zamanı ve mantık hatası çalışırken çıkar
  • C. Söz dizimi hatası kod çalışmadan, çalışma zamanı hatası çalışırken çıkar; mantık hatası mesaj vermez
  • D. Çalışma zamanı hatası kod çalışmadan, söz dizimi hatası çalışırken çıkar; mantık hatası mesaj vermez
  • E. Söz dizimi hatası kod çalışmadan, çalışma zamanı hatası çalışırken çıkar; mantık hatası traceback gösterir

18. Aşağıdaki kod neden sorunludur?

try:
    puan = int(satir["puan"])
except:
    puan = 0
  • A. except bloğuna pass yazılmadığı için
  • B. try bloğu tek satırdan oluştuğu için
  • C. except her istisnayı yakaladığı için
  • D. puan değişkeni iki farklı yerde atandığı için
  • E. int() çağrısı try içinde kullanılamadığı için

19. Bütünleştirici uygulamada kodun veri.py, rapor.py ve main.py olarak ayrılmasının gerekçesi nedir?

  • A. Modüller arasında değişkenler paylaşıldığı için
  • B. Üç dosya bir dosyadan daha hızlı çalıştığı için
  • C. Python büyük dosyaları çalıştıramadığı için
  • D. Her modül kendi hatalarını kendiliğinden yakaladığı için
  • E. Okuma, hesaplama ve çalıştırma ayrı sınanabildiği için

20. CSV’den gelen "12,5" değeri uygulamada nasıl işlenir?

  • A. Virgül noktaya çevrilip float() uygulanır
  • B. Değer metin olarak bırakılıp olduğu gibi toplanır
  • C. Değer int() ile tam sayıya çevrilir
  • D. Virgül silinip 125 elde edilir
  • E. Doğrudan float("12,5") çağrılır

21. Ürün adı alanında " Kalem " değeri geldiğinde normalleştirmenin ilk adımı ne olmalıdır?

  • A. Değeri int() ile çevirmek
  • B. Değeri kısaltarak ilk beş karakteri almak
  • C. Değeri olduğu gibi anahtar yapmak
  • D. replace(" ", "") ile bütün boşlukları silmek
  • E. strip() ile baştaki ve sondaki boşlukları kırpmak

22. “Veri yok” durumunda en yüksek ciroyu yapan ürünü bulan fonksiyonun None döndürmesi neden 0 döndürmekten daha açıklayıcıdır?

  • A. None, “kayıt yok” durumunu 0 cirodan ayırır
  • B. None raporda 0 olarak yazdırılır
  • C. return 0 boş sözlükte hata verir
  • D. None çağıran kodda denetim gerektirmez
  • E. None bellekte daha az yer kaplar

23. Uygulamaya yeni bir özellik ekledikten sonra eski assert kontrollerini de yeniden çalıştırmak neden gerekir?

  • A. Yeni kod eski bir davranışı bozmuş olabilir
  • B. assert satırları ilk çalıştırmadan sonra atlanır
  • C. assert satırları zamanla geçersiz olur
  • D. Python eski sonuçları önbelleğe alır
  • E. Yeni özellik eski kontrolleri siler

24. Fiyatı çözen fonksiyonun kabul kriterleri şunlar: "12,5" için 12.5, "0" için 0.0 döner. "-3" ve "abc" için hata vermeden None döner. AI şu sürümü öneriyor:

def fiyat_coz(metin):
    try:
        fiyat = float(metin.replace(",", "."))
    except ValueError:
        return None
    if fiyat <= 0:
        return None
    return fiyat

Bu sürüm hangi kabul kriterini karşılamaz?

  • A. "12,5" için 12.5 döner
  • B. "-3" için None döner
  • C. "0" için 0.0 döner
  • D. "abc" için hata vermeden None döner
  • E. Dört kriteri de karşılar; kod kabul edilebilir

25. Rapor döngüsünde geçersiz kayıtlar için continue kullanmanın amacı nedir?

  • A. Döngüyü tamamen bitirip rapora geçmek
  • B. Bozuk kaydı atlayıp sonraki kayda geçmek
  • C. Bozuk kaydı listeden kalıcı olarak silmek
  • D. Bozuk kaydı düzeltip yeniden denemek
  • E. Kayıt için ekrana bir hata mesajı yazdırmak

1. Doğru: B. Algoritma dilden bağımsızdır; aynı adımlar Python’da da başka bir dilde de yazılabilir. Programı ayıran şey, bir programlama diliyle yazılmış ve çalıştırılabilir olmasıdır.

  • A yanlış: Bu derste Python kullandığımız için ilk akla gelen dil odur. Ama algoritma belirli bir programlama diline bağlı değildir; bir programlama diliyle yazıldığında program olur.
  • C yanlış: Kulağa doğru gelir, çünkü algoritma çoğu zaman özet gibi yazılır. Ama uzunluk ölçüt değildir. Algoritma da ayrıntılı olabilir; bir algoritma sayfalarca sürerken programı birkaç satır olabilir.
  • D yanlış: Algoritmayı çoğu zaman kâğıtta kurduğumuz için akla yatkın gelir. Ama fark nereye yazıldıkları değildir. Algoritma bir çözüm planıdır ve bilgisayarda da tutulabilir.
  • E yanlış: Algoritma sözcüğü matematik derslerinden tanıdık geldiği için akla yatkın gelir. Ama algoritma formül değil, bir işi bitiren sıralı adımlardır. Hesap içermeyen bir iş de algoritmayla anlatılır.

2. Doğru: D. b hesaplandığı anda a hâlâ 10’du, yani b 15 oldu. Sonradan anın değişmesi byi etkilemez.

  • A yanlış: İki satır da yanlış izlenmiş: a eski değerinde, b ise yeni a ile hesaplanmış gibi. Oysa ne a eski değerinde kalır ne de b yeniden hesaplanır.
  • B yanlış: b = a + 5 satırındaki a yüzünden iki adın aynı değeri paylaştığı sanılabilir. Ama b ayrı bir değişkendir ve anın yeni değerini almaz.
  • C yanlış: b doğru bulunmuş ama a ilk değerinde bırakılmış. Üçüncü satır ayı 20 yaptı; print(a) güncel değeri yazar.
  • E yanlış: b bir formül gibi aya bağlı kalıyormuş ve a değişince yeniden hesaplanıyormuş gibi düşünülür. Ama b = a + 5 satırı o andaki sonucu, yani 15’i saklar; b sonradan kendiliğinden güncellenmez.

3. Doğru: E. 45 >= 50 yanlış olduğu için else bloğu çalışır.

  • A yanlış: Program satırları yukarıdan aşağı çalıştırdığı için iki print() de sırayla çalışır sanılabilir. Ama if ve else birbirini dışlar; aynı çalıştırmada yalnız biri çalışır.
  • B yanlış: Kod yukarıdan okununca ilk print() satırı göze çarpar ve çalışacak satır o sanılır. Ama 45 >= 50 yanlıştır; if bloğu atlanır.
  • C yanlış: input() ile gelen değer int() ile çevrildiği için her karşılaştırmadan önce dönüşüm gerekiyor sanılabilir. Ama puan zaten bir sayı; dönüşüme gerek yok.
  • D yanlış: Koşul yanlış olunca if bloğunun atlandığını bilen öğrenci programın bir şey yazmadığını düşünebilir. Ama else tam bu durum için yazılmıştır: koşul yanlışsa else bloğu çalışır.

4. Doğru: D. Koşul her turun başında sınanır; yanlışsa gövde o tur çalışmaz. Koşul ilk turdan önce de sınandığı için döngü gövdesi sıfır kez de çalışabilir.

  • A yanlış: Bu, bazı dillerdeki do-while davranışıdır. Python’ın while yapısı koşulu başta sınar.
  • B yanlış: Koşul while satırında, döngünün girişinde yazıldığı için yalnız girişte bakılıyormuş gibi görünür. Ama koşul her turun başında yeniden sınanır; yoksa döngü hiç bitmezdi.
  • C yanlış: Döngünün durup durmayacağı güncellemeye bağlı olduğu için koşulun güncellemeden hemen sonra sınandığı düşünülebilir. Ama Python gövdenin ortasında durmaz; gövde bitince while satırına döner ve koşula orada bakar.
  • E yanlış: Atamada sağ tarafın bir kez hesaplanıp saklandığı bilindiği için koşulun da böyle çalıştığı sanılabilir. Ama koşulun sonucu saklanmaz; değişkenler değiştikçe her turda yeniden hesaplanır.

5. Doğru: B. Başlangıç dâhil, bitiş hariçtir; 5 üretilmez.

  • A yanlış: range(5) 0’dan başladığı için her range() çağrısı 0’dan başlıyormuş gibi düşünülür. Ama iki sayı verildiğinde ilki başlangıçtır; sayma 1’den başlar.
  • C yanlış: Parantezdeki iki sayı üretilecek değerler gibi okunabilir. Ama bunlar aralığın başı ve sonudur; range() aradaki bütün değerleri üretir.
  • D yanlış: İki sayının yer değiştirdiği düşünülüp geriye sayma beklenebilir. Ama geriye saymak için üçüncü sayı olarak negatif bir adım vermek gerekir; burada adım 1’dir.
  • E yanlış: Günlük dilde “1’den 5’e kadar” dendiğinde 5 de sayılır, bu yüzden range(1, 5) da öyle okunur. Ama bitiş değeri hiçbir zaman üretilmez. 5’i de istiyorsanız range(1, 6) yazılır.

6. Doğru: B. def satırı yalnızca adı ve gövdeyi kaydeder. Gövdeyi çalıştırmaz. Gövde ancak fonksiyon adı parantezle çağrıldığında, o anda çalışır.

  • A yanlış: def satırı da yürütülen bir satır olduğu için gövdenin o anda çalıştığı sanılabilir. Ama tanım gövdeyi hiç çalıştırmaz. Gövde ilk kez ilk çağrıda çalışır.
  • C yanlış: İki satırın yazımı farklı olduğu için parantezin yalnızca birinde bulunduğu sanılabilir. Ama ikisinde de parantez vardır. Tanımda parametreler, çağrıda argümanlar bulunur.
  • D yanlış: print() gibi yerleşik fonksiyonları def yazmadan kullandığımız için def gereksiz görünebilir. Ama kendi fonksiyonunuz def olmadan oluşmaz. Tanım ve çağrı ayrı adımlardır.
  • E yanlış: Programın asıl işi çağrıda yapıldığı için onun başa konacağı düşünülebilir. Ama sıra tam tersi olmalıdır: ad kullanılmadan önce tanımlanır.

7. Doğru: C. Sözleşme, fonksiyonu kullanacak kişinin gövdeyi okumadan bilmesi gereken üç şeydir.

  • A yanlış: “Sözleşme” sözcüğü imza, tarih ve taraf gibi resmî bilgileri çağrıştırır. Ama yazar, dosya ve tarih fonksiyonun ne yaptığını söylemez; sözleşme girdiyi, davranışı ve sonucu anlatır.
  • B yanlış: İyi bir fonksiyonun hızlı da olması beklendiği için bu ölçüler sözleşmeye girecekmiş gibi görünür. Ama hız ve bellek kullanımı başka bir konudur; sözleşme fonksiyonun ne aldığını, ne yaptığını ve ne döndürdüğünü anlatır.
  • D yanlış: Hatalar da fonksiyonun davranışına ait olduğu için bu seçenek eksiksiz görünebilir. Ama sürüm ve modül bilgisi fonksiyonun işini anlatmaz; sözleşmenin üç sorusu girdi, davranış ve sonuçtur.
  • E yanlış: Fonksiyonu anlatırken ilk göze çarpan şey kodun kendisi olduğu için satır, döngü ve değişken sayısı akla gelir. Ama bunlar gövdenin iç ayrıntılarıdır. Fonksiyonu çağıran kişi gövdeyi okumadan da onu kullanabilmelidir.

8. Doğru: C. İndeksler 0’dan başlar; -1 ise son karakteri gösterir.

  • A yanlış: -1 yazımında eksi işareti gözden kaçarsa iki indeks de baştan sayılır ve ikisi de ilk karakter sanılır. Ama -1 baştan değil sondan sayar.
  • B yanlış: İki karakter doğru bulunmuş ama sıraları karışmış: [0] sondan, [-1] baştan okunmuş. Oysa [0] ilk, [-1] son karakterdir.
  • D yanlış: Günlük hayatta saymaya 1’den başlandığı için [0] ikinci karakter, [-1] de sondan ikinci karakter sanılır. Bu [1] ve [-2] sonuçlarıdır; ilk indeks 0’dır.
  • E yanlış: Konum numarası eksi olamazmış gibi göründüğü için hata beklenebilir. Ama Python negatif indeksi kabul eder; negatif indeks metnin sonundan sayar.

9. Doğru: D. Dilimlemede başlangıç dâhil, bitiş hariçtir; 3 numaralı eleman alınmaz.

  • A yanlış: Seçilen değerler doğru bulunmuş, ama dilimin onları tek tek verdiği sanılmış. Dilimin sonucu her zaman tek bir listedir: [20, 30].
  • B yanlış: 1:3 “birden üçe kadar” diye okununca 3 numaralı eleman da dâhil sanılır. Ama bitiş indeksi dilime girmez; indeks 3’teki 40 alınmaz.
  • C yanlış: Günlük sayımda ilk eleman “birinci” olduğu için indeksler 1’den sayılır ve dilim baştan başlıyormuş gibi görünür. Ama indeksler 0’dan başlar; 1 ikinci elemanı, yani 20’yi gösterir.
  • E yanlış: 1:3 iki eleman aldığı için baştaki iki eleman seçilir sanılabilir. Eleman sayısı doğru ama dilim 0’dan değil 1’den başlar.

10. Doğru: A. append() elemanı listenin sonuna ekler. remove() indekse değil değere göre çalışır ve yalnızca ilk eşleşmeyi kaldırır.

  • B yanlış: Ekleme ile silmenin listenin iki ayrı ucunda yapıldığı düşünülünce simetrik görünür. Ama append() sona ekler; son elemanı silmek pop() işidir.
  • C yanlış: İki metot da listeyi değiştirdiği için listeyi değiştiren öteki metotlarla karışabilir. Ama sıralama sort(), boşaltma clear() işidir.
  • D yanlış: String metotları yeni değer döndürdüğü için liste metotlarının da öyle yaptığı sanılır. Ama ikisi de listeyi yerinde değiştirir ve None döndürür.
  • E yanlış: Listelerde çoğu işlem indeksle yapıldığı için remove()un da indeks aldığı sanılır. Ama remove() indeks değil değer alır; indeksle silmek için del ya da pop() kullanılır.

11. Doğru: E. Sözlükte erişim konuma değil anahtara göre yapılır. "fiyat" değere ulaşmak için kullanılan addır, 15 ise o anahtarın değeridir.

  • A yanlış: Tırnak içinde bir ad olduğu için sözlüğün adı sanılabilir. Ama sözlüğün adı urundur.
  • B yanlış: Fiyat gerçekten okunuyor, bu yüzden bir çağrı gibi görünür. Ama metot çağrısı parantezle yazılır; buradaki köşeli parantez erişimdir.
  • C yanlış: Listede köşeli parantez indeks alır ve "fiyat" ikinci sırada durduğu için akla yatkın gelir. Ama sözlükte sıra numarasıyla erişim yapılmaz.
  • D yanlış: Köşeli parantezin içine yazılan şey okunan veri gibi görünür. Ama değer 15’tir; "fiyat" ona ulaşmak için kullanılan addır.

12. Doğru: E. in sözlükte anahtarları arar, değerlere bakmaz. "Sefiller" bir değerdir; anahtarlar "baslik" ve "sayfa"dır. Değerlerde aramak için in kitap.values() yazılır.

  • A yanlış: get() bulamadığı anahtarda None döndürdüğü için bu davranış akla gelir. Ama in işleminin sonucu her zaman bir bool değeridir.
  • B yanlış: kitap["Sefiller"] yazılsaydı gerçekten KeyError alınırdı. Ama in hata vermez; çoğu zaman tam da hatadan kaçınmak için kullanılır.
  • C yanlış: "Sefiller" gerçekten "baslik" anahtarının değeridir, bu yüzden bu eşleşme akla gelir. Ama in anahtar döndürmez; sonucu True ya da False olur.
  • D yanlış: "Sefiller" sözlüğü yazdırınca gerçekten görünür, bu yüzden akla yatkın gelir. Ama bir değer olarak durur; in varsayılan olarak anahtarlara bakar.

13. Doğru: B. İki erişim art arda yapılır: önce ogrenciler[2] listeden 2 numaralı kaydı seçer, sonra ["puan"] o kaydın puan alanını okur. İlk köşeli parantezde indeks, ikincisinde anahtar vardır.

  • A yanlış: Erişim sağdan sola okunursa puan bir liste gibi görünür. Ama ifade soldan sağa çözülür: ilk köşeli parantez ogrenciler listesine aittir.
  • C yanlış: 2 numaralı indeksin üçüncü kayda denk geldiğini bilen öğrenci bu kayda bir işlem yapıldığını düşünebilir. Ama erişim hiçbir şeyi silmez; silmek için remove() ya da pop() gerekir.
  • D yanlış: Köşeli parantez atamada da kullanıldığı için ifade bir değeri yerleştiriyormuş gibi okunabilir. Ama = yok; değer yalnızca okunuyor.
  • E yanlış: "puan" bütün kayıtlarda bulunan bir alan olduğu için hepsine birden bakıldığı sanılabilir. Ama [2] tek bir kayıt seçer ve yalnız onun alanı okunur.

14. Doğru: A. append() kaydın kopyasını değil, o kayda giden referansı ekler; iki liste aynı sözlüğü paylaşır. Filtrelenmiş listedeki bir kaydı değiştirirseniz ilk listedeki kayıt da değişir. Bağımsız kayıt gerekiyorsa ogrenci.copy() kullanılır.

  • B yanlış: Sayılarla çalışırken paylaşım fark edilmediği için böyle sanılabilir. Ama append() hiçbir türü kopyalamaz; her zaman referans ekler.
  • C yanlış: Filtrelenmiş liste ilk listeden doğduğu için onun kopyası sanılabilir. Ama gecenler boş bir listeyle başlayan ayrı bir listedir; ortak olan, içine eklenen sözlüklerdir.
  • D yanlış: Kayıtların döngü sırasında paylaşıldığını, sonra ayrıldığını düşünmek iki davranışı uzlaştırıyor gibi görünür. Ama döngü bitince de kopya oluşmaz; tek bir sözlük vardır.
  • E yanlış: Kopyalanmayan şeyin değişmez olduğu düşünülebilir. Ama sözlük değiştirilebilirdir ve copy() ile kopyalanabilir.

15. Doğru: D. "w" ile açılan dosyanın eski içeriği silinir ve dosya baştan yazılır. Var olan veriyi korumak istiyorsanız "a" kullanılır; yeni içerik dosyanın sonuna eklenir.

  • A yanlış: İkisi de yazma kipi olduğu için aynı biçimde yazdıkları sanılabilir. Ama "w" dosyayı açtığı anda eski içeriği siler; yalnızca "a" sona ekler.
  • B yanlış: "r" dosya yoksa gerçekten hata verir, bu yüzden öteki kiplerin de öyle davranacağı sanılır. Ama "w" ve "a" dosya yoksa oluşturur.
  • C yanlış: Kip harflerinin anlamı akılda kalmazsa "w" ile "a" kolayca yer değiştirir. Ama "w" baştan yazar, "a" (“append”, eklemek) sona ekler; hiçbir kip içeriği yalnızca silmek için açılmaz.
  • E yanlış: Kip harflerinin bir kısmı ikili dosyalarla ilgili olduğu için karışabilir. Ama ikili kip için "b" eklenir; "a" da metin kipidir.

16. Doğru: D. read() dosyanın tamamını tek bir metin olarak verir. readlines() ise her satırı bir eleman olan bir liste döndürür. Satır satır işlemek istiyorsanız readlines() ya da doğrudan dosya üzerinde for kullanılır.

  • A yanlış: İki ad birbirine benzediği için türler kolayca karışır. Ama iki tür ters yazılmış; çoğul ad readlines() listeyi verir.
  • B yanlış: Dosya satırlardan oluştuğu için her okumanın satır listesi vereceği sanılabilir. Ama read() tek bir string döndürür.
  • C yanlış: Dosyada sayılar yazılıysa read() sonucunun sayı olacağı düşünülebilir. Ama dosyadan okunan içerik her zaman metindir.
  • E yanlış: İkisi de dosyanın bütün içeriğini okuduğu için akla yatkın gelir. Ama readlines() bu içeriği satırlara bölüp liste döndürür.

17. Doğru: C. 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ış: Üçünde de program bir noktada beklenmedik davranır, bu yüzden aynı anda çıktıkları sanılabilir. Ama söz dizimi hatasında kod hiç çalışmaya başlamaz, mantık hatası ise hiç mesaj vermez.
  • B yanlış: Söz dizimi hatası kod çalışmadan çıktığı için sessiz kaldığı düşünülebilir. Ama Python söz dizimi hatasında SyntaxError mesajı ve satır bilgisi gösterir; mesaj vermeyen mantık hatasıdır.
  • D 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ış: “Hata” sözcüğü bir mesaj beklentisi doğurduğu için mantık hatasının da traceback göstereceği sanılır. Ama mantık hatası mesaj vermez; program çalışır, yalnızca sonuç yanlıştır. Bu yüzden bulunması da zordur.

18. Doğru: C. except satırında tür belirtilmediği için 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ış: Boş geçilen except örneklerinde pass görüldüğü için her except bloğunda zorunlu sanılabilir. Ama pass yalnızca blok boş kalacaksa yazılır; burada blokta puan = 0 satırı var.
  • 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.
  • D 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.
  • E 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.

19. Doğru: E. Üç sorumluluk ayrı dosyalara ayrılır; her parça tek başına denenip düzeltilebilir. Ciro yanlış çıkarsa sorun ya okuyan ya da hesaplayan dosyadadır; dosyalar ayrı olduğu için arama bu iki yerle sınırlı kalır.

  • A yanlış: Üç dosya aynı uygulamanın parçası olduğu için adları ortak kullanacağı sanılabilir. Ama her modülün kendi ad alanı vardır; paylaşım kendiliğinden olmaz.
  • B yanlış: Düzenli kodun daha hızlı çalışacağı düşünülebilir. Ama modüllere ayırmak hız kazandırmaz.
  • C yanlış: Uzun bir dosyada çalışmak zorlaştığı için Python’ın da zorlandığı sanılabilir. Ama böyle bir sınır yoktur.
  • D yanlış: Küçük modüllerin daha güvenli olduğu fikri bu şıkkı cazip kılar. Ama hata yakalama yine açıkça yazılır.

20. Doğru: A. Ondalık virgül noktaya çevrildikten sonra float() uygulanır; çevrilemeyen değerler geçersiz kayıt sayılır. Bu dar bir sözleşmedir ve yalnızca virgülün ondalık ayraç olduğu bilinen veride geçerlidir.

  • B yanlış: Değer ekranda sayı gibi göründüğü için dönüşüm gereksiz sanılabilir. Ama metinler sayı gibi toplanmaz; + onları yan yana ekler.
  • C yanlış: int() en sık kullanılan dönüşüm olduğu için ilk akla gelir. Ama int() de virgüllü metni çeviremez; ayrıca ondalık kısım kaybolur.
  • D yanlış: Virgül sorun çıkardığı için onu silmek en kısa çözüm gibi görünür. Ama virgülü silmek değeri on kat büyütür.
  • E yanlış: Türkçede 12,5 doğru bir sayı yazımı olduğu için akla yatkın gelir. Ama bu çağrı ValueError verir; Python ondalık ayracı olarak noktayı bekler.

21. Doğru: E. Görünmeyen boşluklar, gözle aynı görünen iki değeri farklı gruplara düşürür.

  • A yanlış: int() sayı metnindeki boşlukları kendisi kırptığı için burada da işe yarayacağı sanılabilir. Ama ad bir metindir; int(" Kalem ") ValueError verir.
  • B yanlış: Kısa ve eşit uzunlukta anahtarlar düzenli göründüğü için akla gelebilir. Ama " Kalem " için ilk beş karakter " Kal" olur, boşluk sorunu çözülmez. Farklı ürünlerin ilk beş harfi de aynı olabilir.
  • C yanlış: Boşluklar ekranda görünmediği için değer zaten temiz sanılır. Ama " Kalem " ile "Kalem" farklı anahtarlardır ve ayrı gruplara düşer.
  • D yanlış: Sorun boşluk olduğu için bütün boşlukları silmek daha kesin bir çözüm gibi görünür. Ama bu, "Kurşun kalem" gibi iki kelimeli ürün adlarını da bozar.

22. Doğru: A. Hiç geçerli kayıt olmaması ile en yüksek cironun sıfır çıkması farklı durumlardır. Raporu okuyan kişi “hiç geçerli kayıt yok” ile “kayıt var ama en yüksek ciro 0” durumlarını ayırt edebilmelidir.

  • B yanlış: İkisi de “değer yok” gibi algılandığı için ekranda aynı göründükleri sanılabilir. Ama print(None) ekrana None yazar; 0 yazmaz.
  • C yanlış: Boş veride hesap yapmanın hata verdiğini bilen öğrenci 0 döndürmenin de hata vereceğini düşünebilir. Ama return 0 hata vermez; sorun, 0’ın gerçek bir ciro gibi görünmesidir.
  • D yanlış: None sorunu kendisi bildiriyormuş gibi göründüğü için başka işe gerek kalmadığı sanılabilir. Ama tersi doğrudur: çağıran taraf sonucu is None ile denetlemelidir, yoksa hata daha ileride çıkar.
  • E yanlış: None “boş” demek olduğu için daha hafif sanılabilir. Ama bellek bu kararın gerekçesi değildir.

23. Doğru: A. Yeni kod daha önce doğru çalışan bir davranışı bozmuş olabilir; bunu eski kontroller yakalar. Kontroller silinmeyip saklanırsa, bir değişikliğin fark edilmeden bozduğu davranış da görülür.

  • B yanlış: Bir kez geçen kontrolün bir daha sınanmayacağı düşünülebilir. Ama assert satırları her çalıştırmada yeniden sınanır; yeniden çalıştırmak, yeni kodun eski bir davranışı bozup bozmadığını görmek içindir.
  • C yanlış: Eski kodun “eskidiği” düşüncesi akla yatkın gelir. Ama assert satırları geçersizleşmez; her çalıştırmada yeniden sınanırlar.
  • D yanlış: Bazı araçlar sonuçları sakladığı için Python’ın da öyle yapacağı sanılabilir. Ama böyle bir önbellek yoktur.
  • E yanlış: Kod değişince eski satırların da gittiği düşünülebilir. Ama kontroller siz silmedikçe yerinde durur.

24. Doğru: C. "0" sayıya çevrilir ve 0.0 olur. Ama fiyat <= 0 koşulu 0’ı da yakalar ve fonksiyon None döndürür. Kriter fiyatın 0 olabileceğini söylüyor; koşulun fiyat < 0 olması gerekirdi.

  • A yanlış: Ondalık virgül sık sorun çıkardığı için bu kriterin bozulduğu sanılabilir. Ama replace(",", ".") virgülü noktaya çevirir ve float() 12.5 döndürür.
  • B yanlış: Negatif sayı float() ile sorunsuz çevrildiği için fonksiyonun onu kabul edeceği düşünülebilir. Ama -3.0 <= 0 doğrudur ve fonksiyon None döndürür.
  • D yanlış: float("abc") ValueError verdiği için programın duracağı sanılabilir. Ama çağrı try içinde; except ValueError hatayı yakalar ve None döner.
  • E yanlış: Kod düzenli göründüğü ve dört kriterden üçünü karşıladığı için kabul edilebilir sanılır. Ama kriterlerin her biri ayrı ayrı denenmelidir; "0" denenince None döndüğü görülür.

25. Doğru: B. continue bozuk kaydı hesaba katmadan turun kalanını atlar. Geçersiz kaydı baştan atlayınca, geçerli kayıtlar için yazılan kod iç içe if bloklarına girmez.

  • A yanlış: continue ile break döngüyü değiştiren iki komut olduğu için karışır. Ama döngüyü bitiren breaktir; tek bozuk kayıt yüzünden raporun kalanı kaybolurdu.
  • C yanlış: Atlanan kayıt raporda görünmediği için silinmiş sanılabilir. Ama continue listeden bir şey silmez.
  • D yanlış: Geçersiz kayıtla bir şey yapılması gerektiği düşünülebilir. Ama continue düzeltme yapmaz; yalnızca turu atlar.
  • E yanlış: Bozuk kayıtta çoğu zaman bir uyarı yazdırıldığı için akla yatkın gelir. Ama continue kendiliğinden bir şey yazmaz; mesaj için ayrıca print() gerekir.

Dönem özeti

Bu derste Python’ın söz diziminin yanında bir çalışma sırası da öğrendik:

problemi anla
   ↓
girdi–işlem–çıktıyı belirle
   ↓
kabul kriterlerini ve sınırları düşün
   ↓
küçük çözüm adımları oluştur
   ↓
kodu oku ve tahmin et
   ↓
çalıştır ve gözlemle
   ↓
hataları ve veri kalitesini kontrol et
   ↓
küçük fonksiyonlara ve gerekirse modüllere ayır
   ↓
veriyi uygun yapıda tut
   ↓
sonucu testlerle doğrula

Python araçlarını da bu sırayı izlemek için kullandık:

  • Değişkenler ve veri türleri
  • İfadeler ve tür dönüşümleri
  • Koşullar
  • while ve for
  • Fonksiyonlar, kapsam ve varsayılan parametreler
  • String işlemleri ve metin normalleştirme
  • Liste, demet, sözlük ve küme
  • Dosya ve CSV
  • İstisnalar, modüller ve main guard
  • assert, sınır durumları ve adım adım hata ayıklama

Kırtasiyenin gün sonu raporu da bu sıranın küçük bir örneğiydi: önce sahibin kurallarını ve sınır durumlarını düşündük, sonra adımları küçük fonksiyonlara böldük, en son raporu örnek kayıtlarla ve assert satırlarıyla denedik.

İleriki derslerde yeni yapılar ve daha güçlü geliştirme araçları göreceksiniz. AI araçları ve kodlama agent’ları (coding agent: kodu kendi başına yazıp çalıştırabilen AI aracı) daha çok iş üstlenebilir. Ama ilke aynı kalır: kodu kim yazmış olursa olsun, onu anlayabilmeli, ne yaptığını açıklayabilmeli ve doğrulayabilmelisiniz.

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

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

  • Kodu okuma, hesaplama ve çalıştırma modüllerine ayırmanın gerekçesini açıklar.
  • CSV alanlarını güvenli biçimde çözer ve geçersiz kaydı ayıklar.
  • Türkçe metin normalleştirmesini ürün adlarına uygular.
  • “Veri yok” durumunu None ile raporlar.
  • Değişiklikten sonra eski doğrulama kontrollerini yeniden çalıştırır.
  • AI’ın önerdiği kodu kabul kriterleriyle değerlendirir.
  • Rapor döngüsünde continue ve get() kalıplarını uygular.
Başa dön