koddla

Yazılımcıları bilgi ile güçlendirir.

Döngüler

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 beraberr
  • for <değişken1>, <değişken2> in zip(<yinelenebilir öğe1>, <yinelenebilir öğe2>):

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.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Back to top