Python'da tekrar eden işler için iki döngü vardır: for bir dizinin, listenin, metnin ya da başka bir yinelenebilir (iterable) nesnenin elemanlarını sırayla dolaşır; while ise bir koşul doğru olduğu sürece aynı bloğu yeniden çalıştırır. Sayı aralığı gerektiğinde range(), sıra numarası gerektiğinde enumerate(), birden çok listeyi yan yana dolaşmak için zip() kullanırsınız. break döngüden çıkar, continue sıradaki tura geçer, döngünün else bloğu ise döngü break olmadan bittiğinde çalışır.
Bu yazıda iki döngüyü resmî Python belgelerindeki (Tutorial ve Language Reference) kurallara dayanarak anlatıyoruz: döngünün içeride nasıl işlediğini, sık kullanılan yardımcı fonksiyonları, döngü else bloğu gibi çoğu kişinin bilmediği ayrıntıları ve döngü içinde koleksiyon değiştirmek gibi sık yapılan hataları. Bütün örnekler Python 3.15.2 ile çalıştırıldı; # çıktı: yorumları gerçek çıktıdır. Konuya yeni başlıyorsanız önce if/elif/else koşulları yazısına göz atmanız işinizi kolaylaştırır.
for döngüsü: elemanları sırayla dolaşmak

C veya Pascal gibi dillerde for çoğunlukla bir sayacı başlangıçtan bitişe kadar artırır. Python'un for deyimi farklı çalışır: Size bir sayaç vermez, verdiğiniz koleksiyonun elemanlarını göründükleri sırayla tek tek bir değişkene atar ve her eleman için bloğu çalıştırır. Liste, demet (tuple), metin (str), sözlük, küme, dosya nesnesi ve range gibi her yinelenebilir nesne for ile dolaşılabilir.
kelimeler = ['elma', 'pencere', 'bilgisayar']
for k in kelimeler:
print(k, len(k))
# çıktı: elma 4
# çıktı: pencere 7
# çıktı: bilgisayar 10
for harf in 'çay':
print(harf)
# çıktı: ç
# çıktı: a
# çıktı: yLanguage Reference bu süreci şöyle tanımlar: in sağındaki ifade bir kez değerlendirilir ve ondan bir yineleyici (iterator) oluşturulur. Yineleyicinin verdiği her eleman, normal atama kurallarıyla hedef değişkene atanır ve blok çalışır. Yineleyici tükendiğinde (varsa) else bloğu çalışır ve döngü biter. Atama kuralları geçerli olduğu için hedef tek bir ad olmak zorunda değildir; for ad, puan in ... gibi açma (unpacking) yazımı da kullanılabilir. Bu mekanizmanın ayrıntısı, yani iter() ve next() ile yineleyici protokolü generator ve iterator yazısında ele alınıyor.
range() ile sayı aralıkları
Bir sayı dizisi üzerinde dönmeniz gerektiğinde yerleşik range() kullanılır. Bitiş değeri hiçbir zaman sonuca dahil değildir: range(10) 0'dan 9'a kadar on değer üretir, bu da tam olarak on elemanlı bir dizinin geçerli indeksleridir. İsterseniz başlangıç ve adım (step) da verebilirsiniz; adım negatif olabilir.
print(list(range(5))) # çıktı: [0, 1, 2, 3, 4]
print(list(range(5, 10))) # çıktı: [5, 6, 7, 8, 9]
print(list(range(0, 10, 3))) # çıktı: [0, 3, 6, 9]
print(list(range(10, 0, -3))) # çıktı: [10, 7, 4, 1]
print(list(range(5, 1))) # çıktı: []
print(range(10)) # çıktı: range(0, 10)
print(sum(range(4))) # çıktı: 6
r = range(0, 100, 7)
print(len(r), 49 in r, r[-1]) # çıktı: 15 True 98range(10) yazdırıldığında bir liste değil range(0, 10) görürsünüz. Belgelerin vurguladığı gibi range aslında bir fonksiyon değil, değişmez (immutable) bir dizi tipidir: Elemanları bellekte tek tek tutmaz, istendiğinde üretir. Bu yüzden çok büyük aralıklar bile az yer kaplar; yine de len(), indeksleme ve in testi gibi dizi işlemlerini destekler. Elemanları gerçekten bir liste olarak görmek isterseniz list(range(...)) yazarsınız. Başlangıç bitişten büyük ve adım pozitifse sonuç boştur; böyle bir döngü hiç çalışmaz, hata da vermez.
enumerate(): indeks ve değeri birlikte almak
Başka dillerden gelenlerin ilk refleksi range(len(liste)) ile indeks üzerinden dönmektir. Bu çalışır ama Tutorial, çoğu durumda enumerate() kullanmanın daha rahat olduğunu söyler. enumerate() her turda (sayaç, eleman) çifti verir; sayaç varsayılan olarak 0'dan başlar, start parametresiyle değiştirilebilir.
meyveler = ['elma', 'armut', 'kiraz']
for i in range(len(meyveler)):
print(i, meyveler[i])
# çıktı: 0 elma
# çıktı: 1 armut
# çıktı: 2 kiraz
for sira, meyve in enumerate(meyveler, start=1):
print(f'{sira}. {meyve}')
# çıktı: 1. elma
# çıktı: 2. armut
# çıktı: 3. kirazİkinci yazım hem daha kısadır hem de indeksle elemanı ayrı ayrı okumak zorunda bırakmaz. enumerate() listelerle sınırlı değildir; dosya satırları gibi indekslenemeyen yineleyicilerle de çalışır. Örneğin bir dosyada boş satırların numarasını bulmak için for no, satir in enumerate(dosya, start=1) yazabilirsiniz. Dosya okuma ayrıntıları için dosya okuma ve yazma yazısına bakın.
zip(): birden çok diziyi yan yana dolaşmak
İki veya daha fazla diziyi aynı anda dolaşmak istediğinizde zip() her birinden birer eleman alıp demet (tuple) oluşturur. Belgelere göre zip() tembeldir (lazy): Elemanlar ancak döngü onları istediğinde işlenir. Varsayılan davranışta en kısa dizi bittiğinde durur ve uzun dizilerdeki fazla elemanları sessizce yok sayar.
isimler = ['Ayşe', 'Mehmet', 'Elif']
puanlar = [85, 92, 78]
for isim, puan in zip(isimler, puanlar):
print(isim, puan)
# çıktı: Ayşe 85
# çıktı: Mehmet 92
# çıktı: Elif 78
print(list(zip(range(3), 'abcde'))) # çıktı: [(0, 'a'), (1, 'b'), (2, 'c')]
try:
list(zip(isimler, [85, 92], strict=True))
except ValueError as e:
print(e) # çıktı: zip() argument 2 is shorter than argument 1Sessizce kısaltma, iki listenin aynı uzunlukta olması gerektiği durumlarda hatayı gizler; belgeler de farklı uzunlukların bazen verileri hazırlayan koddaki bir hatadan kaynaklandığını ve bunun programın başka bir yerinde zor bulunan bir hataya dönüşebileceğini söyler. Bu nedenle uzunlukların eşit olmasını beklediğiniz yerlerde Python 3.10 ile gelen strict=True seçeneğini kullanın: Bir dizi diğerlerinden önce biterse ValueError alırsınız. Kısa diziyi bir dolgu değeriyle uzatmak istiyorsanız itertools.zip_longest() vardır; bu modül itertools ve functools yazısında anlatılıyor.
Sözlük, ters sıra ve sıralı dolaşma

Tutorial'ın döngü teknikleri bölümü birkaç kalıbı daha önerir. Sözlükte anahtar ve değeri birlikte almak için items() kullanılır. Bir diziyi tersten dolaşmak için diziyi normal yönde yazıp reversed() içine koyarsınız. Sıralı dolaşmak için sorted() kullanılır; bu fonksiyon yeni bir sıralı liste döndürür ve kaynağı değiştirmez. sorted(set(...)) birlikteliği ise tekrar eden elemanları atıp kalanları sıralı dolaşmanın alışılmış yoludur.
stok = {'kalem': 12, 'defter': 0, 'silgi': 5}
for urun, adet in stok.items():
print(urun, adet)
# çıktı: kalem 12
# çıktı: defter 0
# çıktı: silgi 5
print(list(reversed(range(1, 10, 2)))) # çıktı: [9, 7, 5, 3, 1]
sepet = ['elma', 'portakal', 'elma', 'armut', 'portakal']
for meyve in sorted(set(sepet)):
print(meyve)
# çıktı: armut
# çıktı: elma
# çıktı: portakalSözlükler eklenme sırasını korur, bu yüzden items() anahtarları eklediğiniz sırayla verir. Sözlüğün diğer metotları için sözlük metotları yazısına, sıralama anahtarları (key=) için lambda ve sorted yazısına bakabilirsiniz.
while döngüsü: koşul doğru olduğu sürece
while, kaç tur döneceğinizi önceden bilmediğiniz durumlar içindir. Language Reference'a göre ifade her turun başında test edilir; doğruysa blok çalışır, yanlışsa (bu ilk testte de olabilir) varsa else bloğu çalışır ve döngü biter. Koşul ilk seferde yanlışsa blok hiç çalışmaz. Koşul olarak yalnızca karşılaştırmalar değil, doğruluk değeri olan her ifade kullanılabilir: Boş liste, 0, boş metin ve None yanlış sayılır.
geri = 3
while geri > 0:
print('Kalan:', geri)
geri -= 1
print('Başla!')
# çıktı: Kalan: 3
# çıktı: Kalan: 2
# çıktı: Kalan: 1
# çıktı: Başla!
fib = []
a, b = 0, 1
while a < 100:
fib.append(a)
a, b = b, a + b
print(fib) # çıktı: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]Döngü koşulunu etkileyen değişkeni blok içinde güncellemeyi unutmak sonsuz döngünün en yaygın nedenidir. Yukarıdaki ilk örnekte geri -= 1 satırını silerseniz program durmadan aynı satırı yazar. Etkileşimli kabukta ya da terminalde böyle bir döngüyü Ctrl+C ile kesebilirsiniz; Python bunu KeyboardInterrupt istisnası olarak bildirir.
while True ve break kalıbı
Python'da başka dillerdeki do ... while gibi koşulu sonda test eden bir döngü yoktur; dilbilgisinde yalnızca while ve for bulunur. Bloğun en az bir kez çalışması gerektiğinde while True: ile sonsuz döngü kurulur ve çıkış koşulu blok içinde break ile yazılır. Aşağıdaki örnek kullanıcıdan girdi okuyormuş gibi davranır; input() yerine bir liste yineleyicisi kullandık ki çıktı tekrarlanabilir olsun.
girdiler = iter(['12', 'abc', '-5', 'q', '7'])
toplam = 0
while True:
deger = next(girdiler) # gerçek programda: deger = input('Sayı (q: çık): ')
if deger == 'q':
break
if not deger.lstrip('-').isdigit():
print('Atlandı:', deger)
continue
toplam += int(deger)
print('Toplam:', toplam)
# çıktı: Atlandı: abc
# çıktı: Toplam: 7q geldiğinde döngü biter, bu yüzden listedeki '7' hiç okunmaz. Python 3.8'den beri atama ifadesi (:=, walrus) ile değeri okuyup aynı satırda test edebilirsiniz. Language Reference, if ve while içinde parantezin zorunlu olmadığını söyler; aşağıda okunabilirlik için yine de parantez kullandık:
parcalar = iter(['ilk', 'ikinci', '', 'görülmez'])
while (parca := next(parcalar)):
print(parca)
# çıktı: ilk
# çıktı: ikinciBoş metin yanlış sayıldığı için döngü üçüncü parçada durur. Belgelerdeki tipik kullanım, bir dosyayı while chunk := dosya.read(9000): biçiminde parça parça okumaktır.
break ve continue
break, içinde bulunduğu en içteki for veya while döngüsünü hemen sonlandırır. continue ise bloğun geri kalanını atlayıp bir sonraki tura geçer. Simple statements belgesine göre ikisi de yalnızca bir döngünün içinde yazılabilir; döngü içinde tanımlanan bir fonksiyonun ya da sınıfın gövdesinde kullanılamazlar. Bir for döngüsü break ile biterse döngü değişkeni o anki değerini korur.
secilen = []
for sayi in range(1, 11):
if sayi % 3 == 0:
continue # 3'ün katlarını atla
if sayi > 8:
break # 8'i geçince dur
secilen.append(sayi)
print(secilen) # çıktı: [1, 2, 4, 5, 7, 8]
print(sayi) # çıktı: 10Son satır önemli bir ayrıntıyı gösterir: Döngü 9'u continue ile atladı, 10'da break çalıştı ve sayi döngüden sonra 10 olarak kaldı. İç içe döngülerde break yalnızca kendi döngüsünü bitirir, dıştaki döngü devam eder. İki döngüden birden çıkmanın temiz yolu, iç içe döngüyü bir fonksiyona taşıyıp sonucu bulunca return etmektir:
def konum_bul(tablo, hedef):
for i, satir in enumerate(tablo):
for j, deger in enumerate(satir):
if deger == hedef:
return i, j # iki döngüden birden çıkar
return None
print(konum_bul([[1, 2], [3, 4]], 3)) # çıktı: (1, 0)
print(konum_bul([[1, 2], [3, 4]], 9)) # çıktı: NoneDöngülerin else bloğu
Python'a özgü bir yapı olan döngü else bloğu, döngü break ile kesilmeden bittiğinde çalışır. for döngüsünde bu, son tur tamamlandıktan sonra; while döngüsünde ise koşul yanlış olduğunda olur. Döngü break ile, return ile ya da bir istisnayla erken biterse else çalışmaz. Tutorial'daki asal sayı örneği bu yapının tipik kullanımıdır; dikkat edin, else içteki if'e değil for'a aittir:
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '=', x, '*', n // x)
break
else:
print(n, 'asal sayı')
# çıktı: 2 asal sayı
# çıktı: 3 asal sayı
# çıktı: 4 = 2 * 2
# çıktı: 5 asal sayı
# çıktı: 6 = 2 * 3
# çıktı: 7 asal sayı
# çıktı: 8 = 2 * 4
# çıktı: 9 = 3 * 3Belgeler bu bloğu anlamanın iki yolunu önerir. Birincisi, else'i döngü içindeki if ile eşleştirilmiş düşünmektir: Döngü boyunca if defalarca test edilir, bir kez doğru olursa break olur; hiç doğru olmazsa dışarıdaki else çalışır. İkincisi, onu try deyiminin else'ine benzetmektir: try'ın else'i istisna olmadığında, döngünün else'i break olmadığında çalışır. En pratik kullanım alanı "aradığımı bulamadım" durumudur; ayrı bir bulundu = False bayrağına gerek kalmaz:
kullanicilar = ['ali', 'zeynep', 'can']
aranan = 'deniz'
for k in kullanicilar:
if k == aranan:
print('Bulundu:', k)
break
else:
print('Bulunamadı:', aranan)
# çıktı: Bulunamadı: denizpass: hiçbir şey yapmayan blok
Python'da her döngü, fonksiyon veya koşul bloğunun en az bir deyim içermesi gerekir. Henüz yazmadığınız bir bloğu yer tutucu olarak bırakmak için pass kullanılır; Python bu satırı sessizce geçer. Tutorial, birçok kişinin aynı amaçla üç nokta (...) yazdığını da belirtir. Üç nokta dil açısından özel bir anlam taşımaz, sadece sabit bir ifadedir ve gelenek olarak yer tutucu gövde yerine kullanılır. while True: pass gibi bir döngü ise işlemciyi boşuna meşgul eder; gerçek kodda bekleme için bu kalıbı kullanmayın.
Döngü içinde koleksiyonu değiştirmek
Tutorial'ın açıkça uyardığı bir konu, bir koleksiyonu dolaşırken aynı koleksiyonu değiştirmenin doğru yapılmasının zor olmasıdır. Liste üzerinde dönerken eleman silerseniz yineleyici bir sonraki indeksten devam ettiği için bazı elemanlar atlanır ve hata almadan yanlış sonuç elde edersiniz. Sözlükte ise boyut değişirse Python döngüyü RuntimeError ile durdurur. Belgelerin önerdiği iki strateji vardır: kopyanın üzerinde dönmek ya da yeni bir koleksiyon oluşturmak.
sayilar = [1, 2, 2, 3]
for s in sayilar:
if s == 2:
sayilar.remove(s)
# ikinci 2 atlandı, bu yüzden listede kaldı:
print(sayilar) # çıktı: [1, 2, 3]
sayilar = [1, 2, 2, 3]
print([s for s in sayilar if s != 2]) # çıktı: [1, 3]
uyeler = {'ali': 'aktif', 'can': 'pasif', 'ece': 'aktif'}
for ad, durum in uyeler.copy().items(): # kopyanın üzerinde dön
if durum == 'pasif':
del uyeler[ad]
print(uyeler) # çıktı: {'ali': 'aktif', 'ece': 'aktif'}
try:
for ad in uyeler:
uyeler['yeni'] = 'aktif'
except RuntimeError as e:
print(e) # çıktı: dictionary changed size during iterationYeni koleksiyon oluşturmanın en kısa yolu yukarıdaki gibi bir liste üreteci (list comprehension) yazmaktır; bu yazım list comprehension yazısında ayrıntılı anlatılıyor.
Döngü değişkeni hakkında üç ayrıntı
Language Reference döngü hedefleriyle ilgili üç noktayı açıkça yazar. Birincisi, for her turda hedef değişkene yeniden atama yapar; blok içinde değişkene başka bir değer vermeniz bir sonraki turu etkilemez. İkincisi, döngü bittiğinde değişken silinmez, son değeriyle kalır. Üçüncüsü, dolaşılan dizi boşsa döngü hiç atama yapmaz; bu durumda değişkeni döngüden sonra kullanmaya çalışırsanız NameError alırsınız.
for i in range(3):
print(i)
i = 10 # sonraki turu etkilemez
print('Döngüden sonra i =', i)
# çıktı: 0
# çıktı: 1
# çıktı: 2
# çıktı: Döngüden sonra i = 10
for j in []:
pass
print(j)
# hata: NameError: name 'j' is not definedPython'da for ya da if bloğu ayrı bir kapsam (scope) oluşturmaz; döngü değişkeni, döngünün içinde bulunduğu fonksiyonun veya modülün değişkenidir. Kapsam kurallarının tamamı kapsam, global ve nonlocal yazısında var.
try/finally ile break ve Python 3.14 uyarısı
Bir break veya continue, finally bloğu olan bir try içinden döngüyü terk ederse önce finally çalışır, sonra döngüden çıkılır. Tersi ise sorunludur: finally bloğunun içinde break, continue veya return yazmak, o sırada yükselmekte olan bir istisnayı sessizce yutabilir. Python 3.14 ile (PEP 765) derleyici bu durumda SyntaxWarning vermeye başladı. Python 3.15.2'de aşağıdaki kod çalışır ama önce SyntaxWarning: 'break' in a 'finally' block uyarısı basılır. İstisna yönetimi try/except yazısında anlatılıyor.
for i in range(3):
try:
print('deneme', i)
finally:
break # SyntaxWarning: 'break' in a 'finally' blockfor mu while mı?

| Durum | Tercih | Neden |
|---|---|---|
| Bir listenin, metnin, sözlüğün elemanlarını işlemek | for | Elemanları doğrudan verir, sayaç gerekmez |
| Belirli sayıda tekrar | for + range() | Bitiş ve adım baştan bellidir |
| İndeks ve eleman birlikte | for + enumerate() | range(len()) kalıbından kısa ve okunaklı |
| Birden çok diziyi eşleştirmek | for + zip() | Uzunluk kontrolü için strict=True eklenebilir |
| Tur sayısı önceden bilinmiyor | while | Koşul her turun başında test edilir |
| En az bir kez çalışmalı | while True + break | Python'da do-while yoktur |
| Arama yapıp bulunamadığını bildirmek | for + else | Bayrak değişkenine gerek kalmaz |
Sık yapılan hatalar
- range bitişini dahil sanmak:
range(1, 10)10'u içermez. 1'den 10'a kadar saymak içinrange(1, 11)yazın. - Dolaşırken listeden silmek: Hata vermez ama elemanları atlar. Kopyanın üzerinde dönün ya da yeni liste oluşturun.
- while koşulunu güncellememek: Sonsuz döngü oluşur. Koşuldaki değişkenin blok içinde değiştiğinden emin olun.
- else'i if'e ait sanmak: Döngü
else'i girintisiylefor/whilehizasında durur ve yalnızcabreakolmadığında çalışır. - i++ yazmak: Python'da artırma operatörü yoktur;
i++satırıSyntaxError: invalid syntaxverir.i += 1kullanın. - zip ile farklı uzunluktaki listeleri fark etmemek: Uzunlukların eşit olması gerekiyorsa
strict=Trueekleyin. - break'in iki döngüden çıkacağını sanmak: Yalnızca en içteki döngüyü bitirir; gerekirse kodu fonksiyona taşıyıp
returnkullanın.
Sık Sorulan Sorular
Python'da do-while döngüsü var mı?
Hayır. Python'un bileşik deyimleri arasında yalnızca while ve for döngüleri vardır. Bloğun en az bir kez çalışmasını istiyorsanız while True: yazıp çıkış koşulunu blok içinde if ...: break ile kontrol edin.
range() neden liste döndürmüyor?
range, elemanlarını gerektiğinde üreten değişmez bir dizi tipidir; tüm sayıları bellekte tutmadığı için yer kazandırır. Yine de uzunluğu, indekslemeyi ve in testini destekler. Liste gerekiyorsa list(range(...)) yazın.
Döngü else bloğu ne zaman çalışır?
Döngü sonuna kadar çalışıp break olmadan bittiğinde. break, return veya bir istisna döngüyü erken bitirirse else atlanır. Hiç eleman olmayan bir for döngüsünde de else çalışır, çünkü break olmamıştır.
Bir listenin hem indeksini hem elemanını nasıl alırım?
for i, eleman in enumerate(liste): yazın. Sayacın 1'den başlaması için enumerate(liste, start=1) kullanın.
Döngüleri daha kısa yazmanın yolu var mı?
Bir listeden yeni liste üretiyorsanız list comprehension, toplama veya en büyük değer gibi işlemler için sum(), max(), any(), all() gibi yerleşik fonksiyonlar çoğu zaman açık bir döngüden daha kısadır. Büyük veriyi tek seferde belleğe almadan işlemek için generator'lara bakın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Python öğrenme rehberi · if/elif/else koşulları · Liste metotları · List comprehension · Generator ve iterator · itertools ve functools · Fonksiyon tanımlama