Skip to content

Python Generator Kavramı

Bu yazıda Python'daki generator kavramını anlamaya çalışacağız.

  • Generator'lar farklı veri tiplerine(integer, float, string, boolean) sahip değerler dizgesi(sequence) üretirler.
  • Generator'lar bir veri dizgisi(sequence) ürettiği için iterate edilebilir
  • Bir fonksiyonda(methodda) yield anahtar kelimesi kullanarak ya da list comprehension yapısı ile generator oluşturulabilir.

# generator olusturmak icin 1. yontem
def compute(limit):
    for i in range(limit):
        yield i


# generator olusturmak icin 2. yontem
gen = (i for i in range(10))
# >>> gen = (i for i in range(10))
# >>> type(gen)
# <class 'generator'>

# Asagidaki list comprehension LISTE uretir,
# generator DEGIL!
# >>> gen2 = [i for i in range(10)]
# >>> type(gen2)
# <class 'list'>
- Generator tüm veriyi hafızada(memory) tutmaz. - Generator tipindeki bir fonksiyon 1 kere çalışır ve duraklar, iterate edebildiğiniz için fonksiyonu tekrar çağırdığınızda çalışır ve tekrar duraklar. - Iterasyon bittiği halde çağırmaya çalışırsanız StopIteration exception alırsınız. - Generator tipinden list tipine verinizi dönüştürürseniz performans kaybı yaşarsınız. - Iterate edebildiğiniz için generator'daki verilere next() fonksiyonu ile erişebilirsiniz. - Generator exhausted(tükenmiş) olduktan sonra tekrar üzerinde iterate edemezsiniz.

# ornek1.py
def compute(limit):
    for i in range(1, limit+1):
        yield i*i


res = compute(5)
- Verilere erişim 1. yontem

print(next(res))  # 1
print(next(res))  # 4
print(next(res))  # 9
print(next(res))  # 16
print(next(res))  # 25
# print(next(res)) # StopIteration exception
- Verilere erişim 2. Yöntem

for r in res:
    print(r)
- Örnek 2

from time import sleep

def compute1(limit):
    result = []
    for i in range(limit):
        sleep(0.5) # yarim saniye bekle
        result.append(i)
    return result

print(compute1(10)) # 5 saniye sonra result gelecek

def compute2(limit):
    for i in range(limit):
        sleep(0.5) # yarim saniye bekle
        yield i

for c2 in compute2(10):
    print(c2) # yarim saniyede bir degerleri tek tek goster
- Çok fazla sayıda verilerle işlem yaptığımızda bütün verilerin işlenmesinin bitmesini beklemek yerine generator yapısını kullanarak zaman ve performans açısından kazançlı çıkabiliyoruz. - Örnek 3

import time
def compute1(limit):
    res = []
    for i in range(limit):
        res.append(i)
    return res


def compute2(limit):
    for i in range(limit):
        yield i

t1s = time.perf_counter()
compute1(1_000_000)
t1e = time.perf_counter()
print(f"compute1 duration: {t1e-t1s}")
t2s = time.perf_counter()
compute2(1_000_000)
t2e = time.perf_counter()
print(f"compute2 duration: {t2e-t2s}")
- Generator veri yapıları list veri yapılarına göre daha performanslıdır. Yukarıdaki örneği çalıştırınca aşağıdaki sonuçları alıyoruz. Aradaki hız farkını görebilirsiniz.

└─ λ python ornek3.py 
compute1 duration: 0.09740092599986383
compute2 duration: 7.3659998633957e-06 # yani (7.3659998633957)*(10^-6) = 0.0000073659998633957
(env) adnan @ kaya ~/Desktop/py
 └─ λ python ornek3.py 
compute1 duration: 0.0913018249993911
compute2 duration: 1.4819000170973595e-05
(env) adnan @ kaya ~/Desktop/py
 └─ λ python ornek3.py 
compute1 duration: 0.0924550449999515
compute2 duration: 8.418000106757972e-06
(env) adnan @ kaya ~/Desktop/py
 └─ λ python ornek3.py 
compute1 duration: 0.09621888899982878
compute2 duration: 1.4583999472961295e-05
(env) adnan @ kaya ~/Desktop/py
 └─ λ python ornek3.py 
compute1 duration: 0.09367401999952563
compute2 duration: 8.56200040288968e-06
- Görüldüğü gibi listeler hafızada daha çok alan kapladığı gibi generator'lere göre daha yavaş çalışmaktadır.