Ana içeriğe geç
Kesit Python
Temel · Akış kontrolü

Döngüler: for ve while

Yüzlerce siparişi tek tek elden geçir: for ile range, enumerate ve zip; while; break/continue/else; sayaç ve birikim kalıpları; sonsuz döngü tuzağı.

Uygulamada aç, 21 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

Önce küçük bir notDöngülerde sık göreceğin [10, 20, 30] yazımı bir listedir: birkaç değeri sırayla tutar. Şimdilik bu kadarını bilmen yeter; ayrıntısı bir sonraki modülde, Listeler dersinde.

Neden önemli?

Anadolu Market'te bir günde yüzlerce sipariş oluşur. "Her siparişin tutarını topla", "İstanbul'a gidenleri say", "stoğu 5'in altına düşen ilk ürünü bul" gibi işler aynı adımı tekrar tekrar uygulamaktır. Bilgisayarın asıl gücü de budur: tekrar. Döngü (loop) bu tekrarı sen yorulmadan yapar.

for: bir koleksiyonu baştan sona gez

for döngüsü bir koleksiyonun (liste, metin, sözlük, demet, range) her elemanını sırayla bir değişkene koyar ve bloğu çalıştırır.

siparisler = [
    {"id": 1001, "sehir": "Ankara", "tutar": 900.0},
    {"id": 1002, "sehir": "İzmir", "tutar": 820.0},
    {"id": 1003, "sehir": "Ankara", "tutar": 930.0},
    {"id": 1004, "sehir": "İstanbul", "tutar": 450.0},
]

toplam = 0            # birikim (accumulator) değişkeni
for siparis in siparisler:
    toplam += siparis["tutar"]
print("Toplam ciro:", toplam)

ankara_sayisi = 0     # sayaç (counter)
for siparis in siparisler:
    if siparis["sehir"] == "Ankara":
        ankara_sayisi += 1
print("Ankara siparişi:", ankara_sayisi)

Bu iki kalıp, yazacağın döngülerin büyük kısmını kapsar: döngüden önce bir değişkeni başlat (0, boş liste, boş sözlük), döngü içinde güncelle, döngüden sonra kullan.

range: sayı dizisi üret

for i in range(5):          # 0, 1, 2, 3, 4
    print(i, end=" ")
print()
for i in range(1, 6):       # 1..5
    print(i, end=" ")
print()
for i in range(10, 0, -3):  # 10, 7, 4, 1 (adım -3)
    print(i, end=" ")
print()
print(list(range(0, 20, 5)))
Bitiş dahil değilrange(1, 6) 6'yı üretmez. Python'daki tüm aralıklar (dilimleme dahil) "başlangıç dahil, bitiş hariç" çalışır; böylece range(len(liste)) tam olarak indeksleri verir.

enumerate: elemanla birlikte sıra numarası

"Kaçıncı eleman?" sorusuna range(len(liste)) yerine enumerate ile cevap ver; hem eleman hem indeks gelir.

sehirler = ["Ankara", "İzmir", "İstanbul"]
for sira, sehir in enumerate(sehirler, start=1):
    print(f"{sira}. {sehir}")

zip: paralel listeleri yan yana gez

urunler = ["Kulaklık", "Klavye", "Mouse"]
adetler = [12, 3, 25]
for urun, adet in zip(urunler, adetler):
    durum = "AZ" if adet < 5 else "ok"
    print(f"{urun}: {adet} ({durum})")

zip en kısa liste bitince durur. Sözlük gezerken de aynı "çift" mantığı var: for anahtar, deger in sozluk.items():.

while: koşul doğru olduğu sürece

Kaç kez döneceğini baştan bilmiyorsan while kullan. Her turdan önce koşul yeniden kontrol edilir.

bakiye = 1000
ay = 0
while bakiye > 0:
    bakiye -= 350
    ay += 1
    print(f"{ay}. ay sonunda bakiye: {bakiye}")
print("Bakiye", ay, "ayda tükendi")
Sonsuz döngü tuzağıKoşulu değiştiren bir şey yoksa döngü asla bitmez. Yukarıdaki kodda bakiye -= 350 satırını unutursan program donar. Her while yazdığında kendine sor: "Koşulu False yapacak satır hangisi ve kesin çalışıyor mu?"

break, continue ve döngü else

İfadeNe yaparTipik kullanım
breakDöngüyü hemen bitirirAranan bulundu, devam etmeye gerek yok
continueBu turu atlar, sonraki tura geçerİstenmeyen kaydı pas geç
elseDöngü break ile kesilmeden biterse çalışır"Hiçbiri eşleşmedi" mesajı
stok = {"Kulaklık": 12, "Klavye": 3, "Mouse": 25, "Monitör": 0}

# break: ilk kritik ürünü bul
for urun, adet in stok.items():
    if adet < 5:
        print("İlk kritik ürün:", urun)
        break

# continue: stoğu sıfır olanları atla
for urun, adet in stok.items():
    if adet == 0:
        continue
    print(f"{urun} satışa açık ({adet})")

# else: arama sonuçsuz kaldıysa
aranan = "Webcam"
for urun in stok:
    if urun == aranan:
        print("Bulundu")
        break
else:
    print(aranan, "stok listesinde yok")

İç içe döngü

Döngü içine döngü yazabilirsin; iç döngü dış döngünün her turunda baştan sona döner. Toplam tur sayısı çarpılır (3 şehir × 4 ürün = 12 tur), bu yüzden büyük verilerde dikkatli ol.

sehirler = ["Ankara", "İzmir"]
urunler = ["Kulaklık", "Mouse"]
for sehir in sehirler:
    for urun in urunler:
        print(f"{sehir} - {urun}")

"En büyüğü bul" kalıbı

siparisler = [("Ayşe", 900.0), ("Mehmet", 820.0), ("Elif", 1250.0), ("Can", 450.0)]
en_yuksek_ad = None
en_yuksek_tutar = 0
for ad, tutar in siparisler:
    if tutar > en_yuksek_tutar:
        en_yuksek_ad, en_yuksek_tutar = ad, tutar
print(f"En yüksek sipariş: {en_yuksek_ad} ({en_yuksek_tutar} TL)")

# Aynı iş tek satırda (ileride sık kullanacaksın)
print(max(siparisler, key=lambda s: s[1]))
Derinleş

range'i tam tanı

range bir liste değil, sayıları istendikçe üreten hafif bir nesnedir: range(1_000_000) bellekte bir milyon sayı tutmaz. Üç parametresi vardır: başlangıç (dahil), bitiş (hariç) ve adım. Adım negatif olursa geriye sayar; bu durumda başlangıç bitişten büyük olmalıdır, yoksa hiç tur dönmez.

print(list(range(5)))            # 0..4
print(list(range(2, 11, 4)))     # 2, 6, 10
print(list(range(10, 0, -3)))    # geri sayım: 10, 7, 4, 1
print(list(range(0, 10, -1)))    # boş: yön yanlış
r = range(0, 100, 5)
print(len(r), 35 in r, r[-1])    # len, in ve indeks de çalışır

aylar = ["Oca", "Şub", "Mar", "Nis"]
for ay in reversed(aylar):       # listeyi kopyalamadan tersten gez
    print(ay, end=" ")
print()
Sayılarda alt çizgi1_000_000 yazımı Python 3.6'dan beri geçerlidir ve 1000000 ile aynıdır; büyük sayıları okunur kılar. Tutar sabitlerinde (LIMIT = 50_000) kullanman tavsiye edilir.

enumerate ve zip'in ayrıntıları

enumerate(liste, start=1) sıra numarasını 1'den başlatır; raporlarda "1. satır" demek için idealdir. zip ise listelerden en kısası bitince durur ve uzun listedeki fazla elemanları sessizce atar. Veri hatasını gizleyen bu davranış yerine, Python 3.10'dan beri strict=True ile uzunluklar farklıysa hata alabilirsin.

urunler = ["çay", "kahve", "şeker"]
fiyatlar = [120, 340]                    # bir fiyat eksik!
print(list(zip(urunler, fiyatlar)))      # şeker sessizce kayboldu
try:
    for u, f in zip(urunler, fiyatlar, strict=True):
        print(u, f)
except ValueError as h:
    print("Veri hatası:", h)

for no, (u, f) in enumerate(zip(urunler, [120, 340, 45]), start=1):
    print(f"{no}. {u:<6} {f:>4} TL")

Çıktıya dikkat et: strict=True farkı ancak kısa liste bittiği anda anlar; o ana kadarki turlar (çay ve kahve) zaten çalışmıştır. Veritabanına yazma gibi geri alınması zor işlemlerden önce uzunlukları baştan karşılaştırmak (if len(a) != len(b): ...) daha güvenlidir.

Dikkat: zip ve enumerate de range gibi tembeldir ama bir farkla: bir kez tüketilirler. z = zip(a, b) nesnesini bir kez gezdikten sonra ikinci gezişte boş gelir. Nedenini Yineleyiciler (iterator) ve üreteçler (generator) dersinde göreceksin; şimdilik zip'i ya doğrudan döngü başlığında kullan ya da list(zip(...)) ile listeye çevir.

İç içe döngüden çıkmak

break yalnızca içinde bulunduğu döngüyü kırar. İç döngüde aradığını bulduğunda dıştaki döngüyü de durdurmak istiyorsan üç yolun var. En temizi aramayı bir fonksiyona koyup return etmektir; return tüm döngülerden birden çıkar.

YöntemNasıl?Ne zaman?
Fonksiyon + returnBulunca return sonucHemen her zaman en okunaklısı
Bayrak değişkenibulundu = True, iç break, dışta if bulundu: breakFonksiyona ayıramıyorsan
for-elseİç döngü break etmezse else: continue, sonra dışta breakKısa kodlarda; okuması zordur
raflar = [["çay", "kahve"], ["şeker", "tuz", "un"], ["su"]]

def raf_bul(raflar, aranan):
    for i, raf in enumerate(raflar):
        for j, urun in enumerate(raf):
            if urun == aranan:
                return (i, j)          # iki döngüden birden çıkar
    return None

print(raf_bul(raflar, "tuz"), raf_bul(raflar, "pirinç"))

bulundu = None
for i, raf in enumerate(raflar):
    for j, urun in enumerate(raf):
        if urun == "tuz":
            bulundu = (i, j)
            break                       # yalnız iç döngü
    if bulundu:
        break                           # dış döngü
print(bulundu)

while True ve sınırlı deneme

Kaç tur süreceği bilinmeyen ama "şu olunca dur" dediğin döngülerde while True + break kalıbı okunaklıdır: menü döngüleri, kuyruktan iş çekme, kullanıcı doğru girene kadar sorma. Gerçek sistemlerde her zaman bir üst sınır koyarsın: ATM üç yanlış PIN'de kartı bloke eder, bir API isteği beş denemeden sonra vazgeçer.

denemeler = ["1111", "2580", "1234"]     # kullanıcının sırayla girdikleri
dogru_pin = "1234"
hak = 3
deneme = 0
while True:
    if deneme == hak or deneme == len(denemeler):
        print("Kart bloke / deneme bitti")
        break
    girilen = denemeler[deneme]
    deneme += 1
    if girilen == dogru_pin:
        print(f"Giriş başarılı ({deneme}. deneme)")
        break
    print("Hatalı PIN, kalan hak:", hak - deneme)

Döngüde metin biriktirme: join

Döngüde metin += parca yazmak küçük verilerde sorun değildir ama her adımda yeni bir metin oluşturur. Parçaları listede toplayıp sonunda "ayraç".join(liste) demek hem daha hızlı hem de "son elemandan sonra ayraç olmasın" derdini ortadan kaldırır. Kullanmadığın döngü değişkenine _ adını vermek de yaygın bir alışkanlıktır.

sehirler = ["İzmir", "Ankara", "Bursa"]
parcalar = []
for s in sehirler:
    parcalar.append(s.upper())
print(", ".join(parcalar))

for _ in range(3):
    print("-" * 10)

satirlar = []
for no, s in enumerate(sehirler, start=1):
    satirlar.append(f"{no};{s}")
print("\n".join(["no;sehir"] + satirlar))

Son satırdaki \n satır sonu karakteridir; join ile CSV benzeri bir metni tek seferde oluşturduk. Döngülerin yaygın kalıplarını (sayaç, en iyi değer, komşu karşılaştırma, frekans) bir sonraki derste, Döngü kalıpları dersinde sistematik olarak çalışacaksın.

Gerçek işteÜretimdeki döngülerin en sık iki hatası: "bir eksik/bir fazla" (off-by-one) ve sessiz veri kaybı. Birincisi range(1, n) yazıp n'inci elemanı atlamaktır; ikincisi farklı uzunluktaki iki listeyi zip'leyip fazlalığı fark etmemektir. Ekipler bu yüzden indeksle gezmek yerine doğrudan elemanı gezer (for x in liste), paralel listeleri strict=True ile birleştirir ve her yeniden deneme döngüsüne bir üst sınır koyar.
Uzmanlaş

Döngü yerine yerleşik fonksiyon

Toplam için sum(), en büyük/küçük için max()/min(), "hiç var mı / hepsi mi" için any()/all() yazmak hem daha kısa hem de daha hızlıdır; bu fonksiyonlar C ile yazılmıştır. Döngüyü kalıbı anlamak için öğren; işte ise önce yerleşik fonksiyon var mı diye bak. Orta seviyede liste comprehension ile bu kalıplar tek satıra inecek.

Döngü içinde listeyi değiştirme

Üzerinde dolaştığın listeden eleman silmek elemanların atlanmasına yol açar. Ya yeni bir liste kur (kalanlar = [] ve koşula uyanları ekle) ya da kopyası üzerinde dön: for x in liste[:]:.

Sonsuz döngü bazen kasıtlıdır

Sunucular ve menü ekranları while True: ile yazılır ve içeride break ile çıkılır. Tuzak olan "sonsuz" değil, "çıkış yolu olmayan" döngüdür. Kasıtlı yazıyorsan çıkış koşulunu ilk satırlarda açıkça göster.

Alıştırmalara geç (21)