Programlamada en temel fonksiyonlardan biri döngülerdir. Döngüler neredeyse her programlama dili için önemli bir parçadır. Döngüler, geliştiricilerin bir dizi işlemi belirli sayıda tekrar etmesi (yinelemesi) için oluşturulmuş yapılardır. Bu yazıda Python’daki döngüleri ve döngü uygulamalarını inceleyeceğiz.
Syntax
while <boolean ifadesi>:
for <değişken> in <yinelenebilir öğe>:
for <
değişken
> in range(<sayi>):for <
değişken
> in range(<baslangic>, <bitis>):for <
değişken
> in range(<baslangic>, <bitis>, <adim_sayisi>):for i, <
değişken
> in enumerate(<yinelenebilir öğe
>): # index i ile beraberrfor <
değişken
1>, <değişken2> in zip(<yinelenebilir öğe
1>, <yinelenebilir öğe
2>):
While döngüsü
Bir while döngüsü, döngü koşulu yanlış olana kadar yürütülen ifadelerden oluşur. Aşağıdaki kod döngü ifadelerini toplam 4 kez çalıştırır.
i = 0
while i < 4:
# döngü ifadeleri
i = i + 1
Yukarıdaki döngü kolayca daha zarif bir for döngüsüne çevrilebilirken, while döngüleri bazı koşulların karşılandığını kontrol etmek için yararlıdır. Aşağıdaki döngü, myObject hazır oluncaya kadar devam edecektir.
myObject = anObject()
while myObject.isNotReady():
myObject.tryToGetReady()
while
döngüleri herhangi bir koşul olmadan da sayılar kullanılarak çalışabilir:
import cmath
complex_num = cmath.sqrt(-1)
while complex_num: # complex_num sayısı herhangi bir sayı ile değiştirilebilir. ya da True gibi bir bool ifadesi ile de
print(complex_num) # Print 1j sonsuza kadar
Eğer koşul her zaman True ise while loop sonsuza kadar devam eder (infinite loop).
while True:
print "Infinite loop"
# Infinite loop
# Infinite loop
# Infinite loop
# ...
For döngüsü
for
döngüleri list
veya dict
gibi öğe kolleksiyonları üzerinde yineleme yapar. Her öğe için de istenilen kodu çalıştırır.
for i in [0, 1, 2, 3, 4]:
print(i)
Yukarıdaki for
döngüsü bir sayı listesi üzerinde döner.
Her iterasyon i
‘yi listenin bir sonraki öğesi için tanımlar. Yani, önce 0
, sonra 1
, sonra 2
, vb. şeklinde tanımlanır. Çıktı aşağıdaki gibi olacaktır:
0 1 2 3 4
range
fonksiyonu yinelenebilir bir sayı serisi döndürür. For ifadesinde aşağıdaki gibi kullanılabilir:
for i in range(5):
print(i)
Bu kod parçası yukarıdaki kod ile aynı sonucu verir. Burada fark ettiyseniz 5 sayısı bastırılmadı. Çünkü range 0’dan başlayarak 5’e kadar sayı oluşturdu.
Yinelenebilir objeler ve yineleyiciler
for
döngüsü ancak yinelenebilir bir obje üzerinde çalışır. Yinelenebilir objeler __getitem__
veya __iter__
fonksiyonuna sahiptirler. __iter__
fonksiyonu bir yineleyici (iterator) döndürür. Yineleyici, next fonksiyonuna sahip bir objedir.
Döngüleri durdurma ve devam ettirme
break
ifadesi
break
ifadesi bir döngü içerisinde çalıştığında döngü durur:
i = 0
while i < 7:
print(i)
if i == 4:
print("Looptan çıkış")
break
i += 1
break
ifadesinden sonraki ifafdeler artık çalıştırılmayacaktır. break
ifadelerinin ancak döngü içerisinde çalıştığını unutmayın. Fonksiyon içerisindeki break
ifadesi, fonksiyonu çağıran döngüyü sonlandırmak için kullanılmaz.
Yukarıdaki örnenkte break
ifadesi ile karşılandığında döngü 4 numaraya çıktı oluşturmuştu. Son olarak “Looptan çıkış” yazdırıldığına dikkat edin:
0
1
2
3
4
Looptan çıkış
break
ifadeleri aynı zamanda for
döngüleri gibi diğer Python’da bulunan döngü yapıları ile de kullanınlır:
for i in (0, 1, 2, 3, 4):
print(i)
if i == 2:
break
Çıktı:
0 1 2
3 ve 4 sayılarının yazdırılmadığına dikkat edin.
Eğer if ifadesinin karşılığında bir de else ifadesi olsaydı, break ile karşılaşıldığında else ifadesi çalışmayacaktı.
continue
ifadesi
continue
ifadesi şimdiki iterasyonu atlar ve döngüdeki bir sonraki yinelemeye geçer. break
‘de olduğu gibi continue
‘da ancak loop içerisinde kullanılır:
for i in (0, 1, 2, 3, 4, 5):
if i == 2 or i == 4:
continue
print(i)
0
1
3
5
Farkettiyseniz 2
ve 4
yazdırılmadı. Çünkü continue
ifadesi 2 ve 4’e geldiğinde bu satırların atlanmasını sağladı.
İç içe döngülerde break ve continue
break
ve continue
sadece bir seviyedeki döngü için etki eder. Aşağıdaki örnekte içerideki for döngüsü break ile durdurulurken dışarıdaki while döngüsü devam eder:
while True:
for i in range(1,5):
if i == 2:
break # Sadece içerideki döngüyü durdurur!
Python, bir kerede birden fazla döngünün dışına çıkma yeteneğine sahip değildir – bu davranışa ihtiyaç duyulursa, bir veya daha fazla döngüyü bir işleve dönüştürüp break ve return ifadelerinden yardım alınabilir.
Fonksiyon içerisinde return
kullanarak break
uygulamak
Bir işlevin içindeki bir döngüye sahipseniz, bu döngünün içinde return ifadesini kullanarak kodun geri kalanının çalışmasını durdurabilirsiniz (return’den sonra herhangi bir kod çalışmayacaktır):
def break_loop():
for i in range(1, 5):
if (i == 2):
return(i)
print(i)
return(5)
Eğer iç içe döngüleriniz varsa return
ifadesi tüm döngüleri durdurur:
def break_all():
for j in range(1, 5):
for i in range(1,4):
if i*j == 6:
return(i)
print(i*j)
Çıktı:
1 # 1*1
2 # 1*2
3 # 1*3
4 # 1*4
2 # 2*1
4 # 2*2
# return, 2*3 = 6 olduğu için geri kalan ifadeler çalışmadı
Döndürülen dizenin sırasını değiştirme
Döngüler bir dizi üzerinde yineleme yapar. Dolayısıyla döngünün yapıldığı dizenin sırasını değiştirmek beklenmedik sonuçlara yol açabilir (özellikle öğeler eklenir veya çıkarılırsa):
alist = [0, 1, 2]
for index, value in enumerate(alist):
alist.pop(index)
print(alist)
# Çıktı: [1]
Not: list.pop()
listeden öğe çıkarmak için kullanılır.
Bu örnekte ikinci öğe listeden çıkartılmadı. Çünkü yineleme (iterasyon) sıralı bir indexi takip eder. İlk öğe dizeden çıkarıldığında, ikinci öğe ilk öğe haline gelir. Üçüncü öğe de ikinci öğe olur. Ancak index sıralı bir şekilde ilerlediği için ikinci döngü başladığında index ikinci öğeyi ele alır. Haliyle, yukarıdaki döngü iki kere çalışır ve aşağıdaki sonucu üretir:
# İterasyon #1
index = 0
alist = [0, 1, 2]
alist.pop(0) # '0' öğesini kaldırır
# İterasyon #2
index = 1
alist = [1, 2]
alist.pop(1) # '2' öğesini kaldırır
# loop sona erer, ancak alist boş değil:
alist = [1]
Bu sorun yukarıda bahsettiğimiz gibi döngünün indexi takip etmesinden kaynaklanır. Öğeler çıkarıldığında, çıkarılan öğeden sonraki öğelerin indexi değişir. Bundan kurtulmak için döngüyü tersten yinelemeyi deneyebiliriz:
alist = [1,2,3,4,5,6,7]
for index, item in reversed(list(enumerate(alist))):
# tüm çift öğeleri sil
if item % 2 == 0:
alist.pop(index)
print(alist)
# Çıktı: [1, 3, 5, 7]
Döngü yinelemesine sondan başlandığında öğeler listeden çıkarılsa bile önceki öğelerin indexi etkilenmez. Dolayısıyla, alist
içindeki öğeler kolaylıkla silinebilir.
Benzer bir sorun döngü içerisinde listeye öğe eklenmesi sırasında da ortaya çıkar. Bu durum sonsuz bir döngü oluşmasına sebep olur.
alist = [0, 1, 2]
for index, value in enumerate(alist):
# sonsuz döngüden kurtulmak için break
if index == 20:
break
alist.insert(index, 'a')
print(alist)
# Çıktı (kısaca): ['a', 'a', ..., 'a', 'a', 0, 1, 2]
break
ifadesi olmasaydı döngü ram dolana kadar 'a'
öğeğsini listeye eklemeye devam ederdi. Böyle durumlarda yeni bir liste oluşturmak ve öğeyi yeni listeye eklemek tercih edilen yöntemdir.
for
döngüsü kullanırken, liste öğelerini bir geçici değişken ile değiştiremezsiniz:
alist = [1,2,3,4]
for item in alist:
if item % 2 == 0:
item = 'çift'
print(alist)
# Çıktı: [1,2,3,4]
Yukarıdaki örnekte öğeyi değiştirmek orijinal listede değişikliğe sebep olmaz. Bu durumda listenin indexi kullanılarak değişiklik yapılır (alist[2]
). Ya da enumerate()
kullanılabilir:
alist = [1,2,3,4]
for index, item in enumerate(alist):
if item % 2 == 0:
alist[index] = 'çift'
print(alist)
# Çıktı: [1, 'çift', 3, 'çift']
Bir while
döngüsü bu durumlarda daha iyi sonuç verebilir. Eğer listedeki tüm öğeleri silmeyi planlıyorsak:
zlist = [0, 1, 2]
while zlist:
print(zlist[0])
zlist.pop(0)
print('Son: zlist =', zlist)
# Çıktı: 0
# 1
# 2
# Son: zlist = []
Aslında zlist
‘i boş bir listeye eşitlemek de aynı sonucu verecekti:
zlist = []
Yukarıdaki örnek aynı zamanda len()
işlevi ile de desteklenere döngünün bir noktada durmamsı sağlanabilir. Örneğin liste boyutundaki tüm öğeleri sil veya liste listedeki son x öğeyi sil gibi:
zlist = [0, 1, 2]
x = 1
while len(zlist) > x:
print(zlist[0])
zlist.pop(0)
print('Son: zlist =', zlist)
# Çıktı: 0
# 1
# Son: zlist = [2]
Ya da listenin tamamını yineleyip, belirli koşullara uyan öğelerin silinmesini sağlamak gibi: (bu örnekte tüm çift sayıların silinmesi):
zlist = [1,2,3,4,5]
i = 0
while i < len(zlist):
if zlist[i] % 2 == 0:
zlist.pop(i)
else:
i += 1
print(zlist)
# Çıktı: [1, 3, 5]
Bir öğeyi sildikten sonra i’yi artırmadığımıza dikkat edin. zlist[i] öğesini sildiğimiz için, sonraki öğenin indeksi bir azaldı, bu nedenle zlist[i]’i bir sonraki iterasyonda i için aynı değerle kontrol ediyoruz.
Bir listeden istenmeyen öğeleri kaldırmak için uygulanacak diğer bir yöntem listeye istenen öğeleri eklemektir:
zlist = [1,2,3,4,5]
z_temp = []
for item in zlist:
if item % 2 != 0:
z_temp.append(item)
zlist = z_temp
print(zlist)
# Çıktı: [1, 3, 5]
Burada, istediğimiz sonucu önce yeni bir liste içerisindde oluşturuyoruz. Daha sonra isteğe bağlı olarak geçici listeyi orijinal değişkene aktarabiliriz.
Bu düşünce yöntemi ile aslında Python’un en zarif ve güçlü özelliklerinden birini uygulamış olursunuz; list comprehension (liste üreteçleri). List comprehension geçici liste gereksinimini ortadan kaldırır ve daha önce gördüğümüz aynı anda index/öğe değişikliğini gerçekleştirir.
zlist = [1,2,3,4,5]
[item for item in zlist if item % 2 != 0]
# Çıktı: [1, 3, 5]
Liste üzerinde döngüler
Bir liste üzerinde for döngüsü çalıştırmak için aşağıdaki kod parçası yeterlidir:
for x in ['one', 'two', 'three', 'four']:
print(x)
Çıktı:
one
two
three
four
Eğer döngü üzerinde hem list öğelerini hem de indexi elde etmek istiyorsak Python’un enumerate
fonksiyonunu kullanabiliriz:
for index, item in enumerate(['one', 'two', 'three', 'four']):
print(index, '::', item)
enumerate
bir demet oluşturur. Bu demetler indexi (tamsayı) ve öğeyi (listedeki i’ye karşılık gelen öğe) içerir. Yukarıdaki loop aşağıdaki sonucu oluşturur:
(0, '::', 'one')
(1, '::', 'two')
(2, '::', 'three')
(3, '::', 'four')
Listedeki öğeler üzerinde değişiklik yapmak için map
veya lambda
fonksiyonları kullanılabilir:
x = map(lambda e : e.upper(), ['one', 'two', 'three', 'four'])
print(x)
Çıktı:
['ONE', 'TWO', 'THREE', 'FOUR'] # Python 2.x
Not: Python 3.x’te map
bir iterator döndürür. Bu durumda print(list(x))
ile bastırmak gerekir.
else ifadesi ile döngü
Döngüler isteğe bağlı olarak else ifadesine de sahip olabilirler (bu kullanım oldukça nadirdir).
else ifadesi döngü sona erdikten sonra veya koşullu ifadesinin yanlış hale gelmesinden sonra çalıştırılır.
for i in range(3):
print(i)
else:
print('bitti')
i = 0
while i < 3:
print(i)
i += 1
else:
print('bitti')
Çıktı:
0 1 2 bitti
else
ifadesi döngü bir şekilde sonlandırılırsa (break
ifadesi veya bir hata ile) çalışmaz:
for i in range(2):
print(i)
if i == 1:
break
else:
print('bitti')
Çıktı:
0 1
Diğer programlama dillerinin çoğu, döngülerin bu isteğe bağlı else ifadesini barındırmaz. else anahtar kelimesinin kullanımı genellikle kafa karıştırıcı olarak kabul edilir.
Bu ifadenin orijinal konsepti Donald Knuth’e dayanır. else
ifadesinin anlamı kod parçalarımızı programlamanın ilkgünlerinde olduğu gibi veya alt seviye assembly dilindeki gibi if
ve goto
ifadeleri ile yazarsak daha anlaşılır hale gelir.
Örneğin:
while loop_condition():
...
if break_condition():
break
...
Aşağıdakine eş değerdir:
# pseudocode
<<basla>>:
if loop_condition():
...
if break_condition():
goto <<bitis>>
...
goto <<basla>>
<<bitis>>:
Bu iki kod parçası bir else
ifadesi ekleldiğimizde eşdeğer hale gelir.
Örneğin:
while loop_condition():
...
if break_condition():
break
...
else:
print('bitti')
Aşağıdakine eşdeğerdir:
# pseudocode
<<basla>>:
if loop_condition():
...
if break_condition():
goto <<bitis>>
...
goto <<basla>>
else:
print('bitti')
<<bitis>>:
for
döngüsünde else
kullanımı bu şekilde daha anlaşılır olacaktır. Konsept olarak döngü koşulu bir yinelenebilir obje barındırıyorsa True dönecektir.
Bu garip ifadeyi neden kullanmak isteyelim?
for...else
yapısının ana kullanım yerlerinden biri bir arama işlemi olabilir:
a = [1, 2, 3, 4]
for i in a:
if type(i) is not int:
print(i)
break
else:
print("bulunamadı")
Sözlükler üzerinde döngü
Aşağıdaki sözlüğü göz önünde bulunduralım:
d = {"a": 1, "b": 2, "c": 3}
Sözlüğün anahtarları üzerinde döngü kurmak için:
for key in d:
print(key)
Çıktı:
"a"
"b"
"c"
Bu ifade aşağıdakine eşit olacaktır:
for key in d.keys():
print(key)
Ya da Python 2’de:
for key in d.iterkeys():
print(key)
Değerler üzerinde döngü kurmak için ise aşağıdaki ifadeyi kullanırız:
for value in d.values():
print(value)
Çıktı:
1
2
3
Hem anahtar hem değerler için ise:
for key, value in d.items():
print(key, "::", value)
Çıktı:
a :: 1
b :: 2
c :: 3
Not: Python 2’de .keys()
, .values()
ve .items()
bir list
döndürür. Sadece öğeler üzerinde döngü kurmak istersek .iterkeys()
, .itervalues()
ve.iteritems()
kullanırız.
.keys()
ve .iterkeys()
, .values()
ve .itervalues()
, .items()
ve.iteritems()
fonksiyonlarının aralarındaki fark iter*
fonksiyonlarının generator olmasıdır. Dolayısıyla, sözlük öğeleri birer birer değerlendirilir. Öte yandan bir list
objesi döndürüldüğünde tüm öğeler bir listeye paketlenir ve sonradan değerlendirmek üzere sunulur.
Döngüde pass ifadesi
pass
bir null ifadesidir. Kod bloğumuzda Python syntax’ına göre bir ifade yazmak gerektiğinde ancak bu ifadenin programcı tarafından henüz yazılmadığı veya ileride de yazılmayacağı durumlarda kullanılır (örneğin bir for
veya while
döngüsünün gövdesi gibi). Bu kullanım ileride yazılacak kod blokları için bir ayırılmış alan oluşturmak için yararlı olabilir.
for x in range(10):
pass #şuanda buraya ne yazacağımıza karar vermedik, veya ileride yazacağız
Bu örnekte hiç bir şey çalışmayacaktır. Bununla birlikte for
döngüsü hata vermeden tamamlanacaktır. pass
kod bloğunun tamamen yazılmadığı durumlarda da hatasız çalışmasını sağlar.
Benzer şekilde, pass
bir while
döngüsü içinde de kullanılabilir:
while x == y:
pass
Bir listenin farklı bölgelerinde farklı adım sayılarında yineleme yapmak
Uzun bir element listesine sahip olduğunuzu varsayalım ve yalnızca listenin bir kısmı ile ilgileniyorsunuz. Belki de sadece ilk veya son öğeleri incelemek istiyorsanız. Python güçlü bir indeksleme yeteneğine sahiptir.
Aşağıdaki örneğe bakalım:
lst = ['alpha', 'bravo', 'charlie', 'delta', 'echo']
Tüm listeyi döndürmek
Tüm liste üzerinde döngü kurmak için aşağıdakini kullanırız:
for s in lst:
print s[:1] # ilk harfi bastır
for
döngüsü s değişkenine lst
‘in öğelerini atar. Çıktı:
a
b
c
d
e
Çoğu durumda öğenin kendisine ve indexine ihtiyaç duyarız. Bu durumda enumerate
kullanılır:
for idx, s in enumerate(lst):
print("%s, index: %d" % (s, idx))
İndex idx
sıfırdadn başlar ve her iterasyonda artırılır. Çıktı:
alpha, index 0
bravo, index 1
charlie, index 2
delta, index 3
echo, index 4
Alt listeler üzerinde döngü
Eğer listenin bir bölümü üzerinde döngü kurmak istersek range
kullanabiliriz (Python’un index için sıfırdan başladığını unutmayın):
for i in range(2,4):
print("lst index %d için öğe: %s" % (i, lst[i]))
Çıktı:
lst index 2 için öğe: charlie
lst index 3 için öğe: delta
Liste aynı zamanda dilimlenerek de kullanılabilir. Dilimleme notasyonuna göre aşağıdaki örnek index 1’deki öğeden başlar ve son öğeye kadar adım sayısı 2 ile devam eder. Aşağıdaki iki for
döngüsü de eşdeğerdir.
for s in lst[1::2]:
print(s)
for i in range(1, len(lst), 2):
print(lst[i])
Çıktı:
bravo
delta
İndexleme ve dililmleme kendi başlarına incelenmesi gereken konulardır.
Yarım döngü: do-while
Diğer dillerden farklı olarak, Python bir do-until veya bir do-while yapısına sahip değildir. Ancak, aynı amacın elde edilmesi için while ve True ifadeleri bir break ile birleştirilebilir.
a = 10
while True:
a = a-1
print(a)
if a<7:
break
print('Bitti.')
Çıktı:
9
8
7
6
Bitti.
Döngü kurma ve Unpacking
Eğer bir demet üzerinde döngü kurmak istersek:
collection = [('a', 'b', 'c'), ('x', 'y', 'z'), ('1', '2', '3')]
Aşağıdaki gibi bir yapı yerine:
for item in collection:
i1 = item[0]
i2 = item[1]
i3 = item[2]
# ..
Ya da aşağıdakinin yerine:
for item in collection:
i1, i2, i3 = item
#..
Unpacking kullanabiliriz:
for i1, i2, i3 in collection:
# ..
Bu yöntem sadece demeteler için değil çoğu yinelenebilir öğe için çalışır.