Python (3.9.1) Generator
- Bu yazıda Python'daki (3.9.1) 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.
xxxxxxxxxx
# 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.
Örnekler
ornek1.py
xxxxxxxxxx
def compute(limit):
for i in range(1, limit+1):
yield i*i
res = compute(5)
Verilere erisim 1. yontem
xxxxxxxxxx
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
xxxxxxxxxx
##### Verilere erisim 2. yontem
for r in res:
print(r)
ornek2.py
xxxxxxxxxx
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.
ornek3.py
xxxxxxxxxx
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.
xxxxxxxxxx
└─ λ 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
Corey Schafer Kod Örneği Çıktısı
xxxxxxxxxx
└─ λ python generator_people.py
Memory (Before): 24.76953125Mb
people_list Memory (After) : 295.453125Mb
people_list Took 1.5263274680000904 Seconds
people_generator Memory (After) : 25.89453125Mb
people_generator Took 0.09679912100000365 Seconds
- Görüldüğü gibi listeler hafızada daha çok alan kapladığı gibi generator'lere göre daha yavaş çalışmaktadır.
Yorumlar