for, range() ve döngü problem kalıpları

Geçen hafta while ile koşul doğru olduğu sürece tekrar yaptık. Bazen ise kaç tekrar yapacağımız baştan bellidir: 1’den 10’a kadar sayıları işlemek, 7 günlük veri girmek veya 6 taksitlik bir ödeme planı oluşturmak gibi.

Bu tür durumlarda Python’ın for döngüsü ve range() fonksiyonu daha doğrudan bir anlatım sağlar. Bu hafta yalnızca yeni bir döngü sözdizimi öğrenmeyeceğiz; sayma, biriktirme, arama ve özetleme gibi tekrar eden problem kalıplarını tanıyacağız.

Bu hafta neleri yapabilmelisiniz?

Bölümün sonunda:

  • for döngüsünün range() ile nasıl çalıştığını açıklayabilmeli,
  • range() nesnesi ile liste arasındaki farkı başlangıç düzeyinde açıklayabilmeli,
  • range(son), range(baslangic, son) ve range(baslangic, son, adim) biçimlerini kullanabilmeli,
  • Bitiş değerinin range() tarafından dahil edilmediğini pozitif ve negatif adımda hesaba katabilmeli,
  • Sayaç ve biriktirici kullanan basit döngüler yazabilmeli,
  • Belirli bir koşulu sağlayan değerleri sayabilmeli,
  • Bir aralıkta ilk uygun değeri bulmak için break kullanabilmeli,
  • while True ve break ile geçerli girdi gelene kadar tek okuma noktalı döngü kurabilmeli,
  • Gerektiğinde bir yinelemenin kalanını atlamak için continue kullanabilmeli,
  • Özel bir bitirme değeriyle (sentinel) while döngüsünü sonlandırabilmeli,
  • Basit bir tekrar problemini uygun döngü yapısını seçerek çözebilmelisiniz.

for ile belirli sayıda tekrar

range tarafından üretilen değerlerin for döngüsüne sırayla gelmesi.

for ve range akışı

Aşağıdaki program 0, 1, 2, 3 ve 4 değerlerini yazdırır:

for sayi in range(5):
    print(sayi)

range(5) döngü sırasında şu değerleri sağlar:

0, 1, 2, 3, 4

Bitiş değeri olan 5 dahil değildir.

Bu davranış başta alışılmadık gelebilir; ancak aralıkların uzunluğunu hesaplamayı kolaylaştırır. range(5) tam olarak beş değer üretir.

range() bir liste değildir

range(5) ile döngüde 04 değerlerini dolaşabilsek de range() çağrısı doğrudan bir liste oluşturmaz. Python bunu ayrı bir range nesnesi olarak temsil eder:

print(range(5))

Çıktı:

range(0, 5)

Ürettiği değerleri bir kerede görmek isterseniz öğretim amacıyla list() kullanabilirsiniz:

print(list(range(5)))

Çıktı:

[0, 1, 2, 3, 4]
Note

for sayi in range(5): yazarken list(range(5)) yapmanız gerekmez. Döngü range nesnesindeki değerleri doğrudan sırayla kullanabilir. Burada list() yalnızca aralığın içeriğini görünür kılmak için gösterildi.

Tahmin et — range() hangi değerleri üretir?

Aşağıdaki kodu çalıştırmadan önce çıktıyı tahmin edin:

range(2, 9, 2):

  • 2 değerinden başlar,
  • Her adımda 2 artırır,
  • 9 değerine gelmeden durur.

Bu nedenle çıktı 2, 4, 6, 8 olur.

range() biçimleri

range(stop), range(start, stop) ve range(start, stop, step) kullanımlarının ürettiği değerler.

range parametreleri

Üç temel kullanım biçimi vardır:

Yazım Üretilen değerlerin fikri
range(5) 0’dan başla, 5 hariç ilerle
range(2, 6) 2’den başla, 6 hariç ilerle
range(10, 0, -2) 10’dan başla, 0’a gelmeden ikişer azal

Negatif adımda yeni bir “0 özel kuralı” yoktur. Bitiş (stop) değeri her durumda dahil edilmez. Yalnızca ilerleme yönü değişir.

Örneğin:

print(list(range(5, 0, -1)))

şunu verir:

[5, 4, 3, 2, 1]

0 görünmez; çünkü 0, bu çağrının bitiş değeridir. Aynı yarı-açık aralık mantığı pozitif adımda da geçerlidir.

for sayi in range(5, 0, -1):
    print(sayi)

Çıktı:

5
4
3
2
1

Alıştırma — son değeri dahil edin

Amaç 1’den 10’a kadar on sayının tamamını yazdırmaktır. Mevcut kod 10 değerini atlıyor.

range() bitiş değerini düzeltin.

range(1, 11) ifadesini deneyin.

for sayi in range(1, 11):
    print(sayi)

Sayaç ile biriktirici aynı şey değildir

Döngülerde iki değişken rolü sık görülür:

  • Sayaç: kaç kez işlem yapıldığını veya hangi adımda olduğumuzu izler,
  • Biriktirici: toplam, çarpım veya başka bir birikimli sonucu taşır.

Örneğin 1’den 5’e kadar sayıların toplamı:

toplam = 0

for sayi in range(1, 6):
    toplam = toplam + sayi

print(toplam)

Burada sayi, range() tarafından sırayla verilen değer; toplam ise biriktiricidir.

İzleme:

sayi Yeni toplam
1 1
2 3
3 6
4 10
5 15

Toplam değişkeninin her döngü turunda nasıl güncellendiğini gösteren biriktirme kalıbı.

Biriktirme kalıbı

Alıştırma — haftalık çalışma süresini toplayın

Bir öğrencinin her gün sabit 45 dakika çalıştığını ve bunu 7 gün sürdürdüğünü varsayalım. Toplam çalışma süresini biriktiriciyle hesaplayın.

toplam_dakika = toplam_dakika + 45 satırı her yinelemede çalışmalıdır.

toplam_dakika = 0

for gun in range(1, 8):
    toplam_dakika = toplam_dakika + 45

print("Toplam dakika:", toplam_dakika)

Sayma kalıbı

Bazen değerlerin toplamını değil, bir koşulu kaç değerin sağladığını bulmak isteriz.

Örneğin 120 arasında 3 ile tam bölünen kaç sayı olduğunu bulalım:

adet = 0

for sayi in range(1, 21):
    if sayi % 3 == 0:
        adet = adet + 1

print(adet)

Buradaki sayaç her döngüde değil, yalnızca koşul doğru olduğunda artar.

Tahmin et ve çalıştır

Aşağıdaki kod 115 arasında çift sayıların kaç tane olduğunu sayıyor. Çalıştırmadan önce sonucu tahmin edin:

Sonuç 7 olmalıdır: 2, 4, 6, 8, 10, 12, 14.

Arama kalıbı ve break

Bir aralıkta aradığımız ilk değeri bulduğumuzda döngünün geri kalanına ihtiyacımız olmayabilir. break, içinde bulunduğu döngüyü hemen sonlandırır.

Örneğin 50’den büyük ve 7 ile tam bölünen ilk sayıyı bulalım:

for sayi in range(51, 100):
    if sayi % 7 == 0:
        print("Bulundu:", sayi)
        break

İlk uygun değer 56 olduğunda döngü sona erer.

Important

break, “döngünün normal koşulu bitti” anlamına gelmez; programcı döngüyü o noktada bilinçli olarak sonlandırır. Gereksiz break kullanmak kodun akışını zorlaştırabilir. Aranan sonuç bulunduğunda kalan yinelemelerin anlamı yoksa kullanmak uygundur.

Alıştırma — ilk uygun katı bulun

30’dan büyük, 8 ile tam bölünen ilk sayıyı bulun. Mevcut program tüm uygun değerleri yazdırıyor; yalnızca ilkini yazdıracak biçimde değiştirin.

print() satırından sonra aynı girinti düzeyinde break yazın.

for sayi in range(31, 80):
    if sayi % 8 == 0:
        print("Bulundu:", sayi)
        break

Geçerli girdi gelene kadar: while True + break

Geçen hafta input() satırını döngüden önce ve döngü içinde iki kez yazdığımız örneği gördük. Artık break bildiğimiz için aynı akışı tek okuma noktasıyla kurabiliriz:

while True:
    puan = int(input("1-5 arasında puan: "))

    if 1 <= puan <= 5:
        break

    print("Geçersiz değer")

print("Kabul edilen puan:", puan)

while True koşulu kendi başına sonsuza kadar doğru kalır. Bu nedenle bu kalıpta çıkış koşulunun ve break satırının açık olması zorunludur. Geçerli değer geldiğinde break döngüyü sonlandırır; geçersiz değerde yeni yineleme başlar.

Note

Bu örnek de girdinin int() ile dönüştürülebilen bir sayı olduğunu varsayar. Sayıya dönüştürülemeyen metni güvenli biçimde ele almayı 13. haftadaki istisnalar konusunda öğreneceğiz.

continue: bu yinelemenin kalanını atla

continue, döngüyü tamamen bitirmez. Yalnızca o anki yinelemenin geri kalanını atlayıp bir sonraki yinelemeye geçer.

Tek bir basit koşul için continue çoğu zaman gerekli değildir. Örneğin yalnızca saat == 3 durumunu atlamak if saat != 3: ile de rahatça yazılabilir. continue daha çok, işlenecek veriye geçmeden önce birden fazla geçersiz durumu erken elemek istediğimizde ana akışı sadeleştirebilir.

Örneğin ölçüm listemizde -50 derecenin altındaki ve 60 derecenin üzerindeki değerleri geçersiz kabul edelim:

olcumler = [22, -80, 24, 75, 19]

toplam = 0
gecerli_adet = 0

for sicaklik in olcumler:
    if sicaklik < -50:
        continue

    if sicaklik > 60:
        continue

    toplam = toplam + sicaklik
    gecerli_adet = gecerli_adet + 1

print("Geçerli ölçüm:", gecerli_adet)
print("Toplam:", toplam)

Bu örnekte iki farklı reddetme kuralı, asıl işleme kodundan önce görünür. Geçersiz değerlerde continue sonrası toplam ve sayaç güncellenmez; fakat döngü sonraki ölçümle devam eder.

Tip

continue kullanmadan daha kısa ve daha açık bir koşul yazabiliyorsanız onu tercih edin. Ama bir kayıt için birden fazla “bu kaydı işlemeyelim” kontrolü varsa, continue ana işleme yolunu daha az girintili ve daha okunur tutabilir.

Özel bitirme değeri (sentinel)

Kaç veri geleceği baştan belli değilse for range(...) uygun olmayabilir. Kullanıcının özel bir değer girerek işlemi bitirdiği durumlarda geçen haftaki while yapısını kullanabiliriz.

Örneğin harcama tutarları girilsin; -1 girildiğinde giriş bitsin:

toplam = 0
tutar = float(input("Tutar (-1 bitirir): "))

while tutar != -1:
    toplam = toplam + tutar
    tutar = float(input("Tutar (-1 bitirir): "))

print("Toplam:", toplam)

Burada -1 normal bir harcama değildir; yalnızca girişin bittiğini bildiren özel bitirme değeri (sentinel) olarak kullanılır.

Note

Gerçek uygulamada geçerli harcama aralığı ayrıca doğrulanmalıdır. Bu örnekte -1 dışında negatif değer girilmediğini ve kullanıcının boş giriş yapmadığını varsayıyoruz. Kullanıcı yalnızca Enter’a basarsa float("") dönüşümü ValueError üretir; bu tür dönüşüm hatalarını 13. haftada try/except ile ele alacağız.

Hangi döngüyü seçmeliyim?

Basit bir başlangıç kuralı:

Durum Genellikle uygun yapı
Tekrar sayısı baştan belli for + range()
Bir koşul sağlandığı sürece devam while
Özel bitirme değeri gelene kadar devam while
Belirli sayı aralığındaki değerleri işle for + range()

Bu bir yasak listesi değildir. Aynı problem bazen iki yapıyla da çözülebilir. Ama kodun niyetini en açık anlatan yapıyı seçmek önemlidir.

Değiştir — taksit planını inceleyin

Bir ürün 12000 TL ve 6 eşit taksitle ödenecek olsun:

Şunları deneyin:

  1. taksit_sayisi değerini 4 yapın.
  2. İlk ve son ayın ay değerini tahmin edin.
  3. range(1, taksit_sayisi) yazarsanız son taksitte ne olur?
  4. Her ayın başındaki ve sonundaki kalan değerini küçük bir izleme tablosuna yazın.

Üret — aylık abonelik borcunu azaltın

Bir cihaz 9000 TL borçla alınmış ve her ay 1500 TL ödeme yapılacak. 6 ay boyunca ödeme sonrasındaki kalan borcu yazdıran bir program yazın.

Başlangıç kodu:

Kabul kriterleri:

  • for ve range() kullanılmalı,
  • Aylar 1’den 6’ya kadar işlenmeli,
  • Her ay kalan_borc değerinden aylik_odeme çıkarılmalı,
  • Ay numarası ve kalan borç yazdırılmalı,
  • Son ay sonunda kalan borç 0 olmalı.

for ay in range(1, 7): ile başlayabilirsiniz.

kalan_borc = 9000
aylik_odeme = 1500

for ay in range(1, 7):
    kalan_borc = kalan_borc - aylik_odeme
    print("Ay:", ay, "Kalan borç:", kalan_borc)

İç içe döngü ne zaman gerekir?

Bir tekrarın içinde başka bir tekrar gerektiğinde döngüler iç içe olabilir. Başlangıç düzeyinde bunu yalnızca problem gerçekten iki boyutlu tekrar gerektiriyorsa kullanacağız.

Örneğin iki katlı ve her katta üç odalı bir binanın oda etiketlerini üretelim:

for kat in range(1, 3):
    for oda in range(1, 4):
        print("Kat:", kat, "Oda:", oda)

Dış döngünün her bir yinelemesinde iç döngü baştan sona çalışır. Toplam 2 × 3 = 6 satır üretilir.

Bu hafta karmaşık desen çıktıları üretmeyeceğiz; önemli olan “iki bağımsız tekrar boyutu varsa iç içe döngü gerekebilir” fikridir.

Bölüm özeti

Bu hafta belirli sayıda tekrarı for ve range() ile ifade ettik ve sık kullanılan döngü kalıplarını gördük.

  • range() bir liste değil, aralıktaki değerleri dolaşmaya yarayan ayrı bir range nesnesidir; değerleri görmek için öğretim amacıyla list(range(...)) kullanılabilir.
  • range() bitiş değerini pozitif ve negatif adımda dahil etmez.
  • range(baslangic, son, adim) ile başlangıç ve ilerleme miktarı belirlenebilir.
  • Sayaç kaç olay olduğunu; biriktirici toplam gibi biriken sonucu tutar.
  • Koşulu sağlayan değerleri saymak için sayaç yalnızca if doğru olduğunda artırılabilir.
  • break aranan sonuç bulunduğunda veya geçerli girdi alındığında döngüyü tamamen bitirebilir.
  • while True + break, geçerli girdi gelene kadar sorma kalıbında yinelenen ilk okuma satırını kaldırabilir.
  • continue yalnızca mevcut yinelemenin kalanını atlar; özellikle birden fazla erken reddetme kontrolünde yararlı olabilir.
  • Tekrar sayısı baştan biliniyorsa for, koşula bağlı belirsiz tekrar için while çoğu zaman daha açıklayıcıdır.
  • Özel bitirme değeri (sentinel) veri girişinin sona erdiğini bildirmek için kullanılabilir; boş veya dönüştürülemeyen girdi ayrıca ele alınması gereken farklı bir durumdur.
  • İç içe döngü, problemde gerçekten iki tekrar boyutu olduğunda kullanılmalıdır.

Kendinizi kontrol edin

Kodu çalıştırmadan cevaplamaya çalışın:

  1. range(1, 5) hangi değerleri üretir?
  2. print(range(5)) neden [0, 1, 2, 3, 4] yazdırmaz? Bu değerleri nasıl görünür kılabilirsiniz?
  3. range(2, 11, 2) hangi değerleri üretir?
  4. range(5, 0, -1) neden 0 değerini üretmez?
  5. 1100 arasındaki sayıların toplamını tutan değişken sayaç mı, biriktirici mi olur?
  6. break ile continue arasındaki temel fark nedir?
  7. while True ile geçerli girdi isterken döngünün gerçekten sonlanmasını sağlayan satır nedir?
  8. range(1, 7) neden altı ayı temsil eder?
  9. Sentinel örneğinde kullanıcının yalnızca Enter’a basması neden ayrı bir hata durumudur?
  10. İki kat ve dört oda için iç içe döngü toplam kaç yineleme yapar?

Bir sonraki bölümde tekrar eden kod parçalarını fonksiyonlara ayıracak; parametreler ve dönüş değerleriyle problemi daha küçük parçalara böleceğiz.

Back to top