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 bölümün kapsamı
range()nesnesinin ürettiği değerler ve listeden farkırange()biçimleri ve bitiş değerinin dışarıda kalması- sayma ve biriktirme kalıpları
- arama kalıbında
breakile erken bitirme continueile yalnızca o yinelemeyi atlamawhile Truevebreakile geçerli girdi kalıbı, sentinel ayrımı- probleme göre
forilewhilearasında seçim
enumerate()vezip()kullanımı- ikiden çok katmanlı iç içe döngüler
Bu başlıklar konunun devamıdır; ileride karşınıza çıkar ama bu derste ezberlemeniz beklenmiyor.
range(1, 5) neden 5 değerini üretmiyor?
Bu tek kural, dönem boyunca yapacağınız hataların önemli bir bölümünü açıklar. Bölümün ikinci yarısı ise tekrar eden problemleri adlandırır: saymak, biriktirmek, aramak ve erken çıkmak birbirinden ayrı kalıplardır.
for ile belirli sayıda tekrar
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 0–4 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]
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):
2değerinden başlar,- Her adımda
2artırır, 9değerine gelmeden durur.
Bu nedenle çıktı 2, 4, 6, 8 olur.
range() biçimleri
Üç 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 |
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 1–20 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 1–15 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.
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)
breakGeç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.
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.
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.
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:
taksit_sayisideğerini4yapın.- İlk ve son ayın
aydeğerini tahmin edin. range(1, taksit_sayisi)yazarsanız son taksitte ne olur?- Her ayın başındaki ve sonundaki
kalandeğ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:
forverange()kullanılmalı,- Aylar
1’den6’ya kadar işlenmeli, - Her ay
kalan_borcdeğerindenaylik_odemeçıkarılmalı, - Ay numarası ve kalan borç yazdırılmalı,
- Son ay sonunda kalan borç
0olmalı.
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.
Tek sayfa özet
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ı birrangenesnesidir; değerleri görmek için öğretim amacıylalist(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
ifdoğru olduğunda artırılabilir. breakaranan 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.continueyalnı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çinwhileç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.
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.
Bu bölümün kazanımları
Bu bölümü bitiren öğrenci:
range()nesnesinin ürettiği değerleri belirler ve listeden farkını açıklar.range()biçimlerini uygular ve bitiş değerinin dışarıda kaldığını hesaba katar.- Sayma ve biriktirme kalıplarını
forile kurar. - Arama kalıbında
breakile döngüyü erken bitirir. continueile yalnızca o yinelemenin kalanını atlar.while Truevebreakile geçerli girdi kalıbını kurar, sentinel’den ayırır.- Problemin yapısına göre
forilewhilearasında seçim yapar.