Generators, yield

Kategori: Python , 07 Eylül 2019 , JanFranco


Generator'lar, iterator gibi davranan fonksiyonları tanımlamamıza yararlar. Anlamak için bir örnek düşünelim, elimizde büyük bir veriseti mevcut. Bu verisetini bir fonksiyona göndereceğiz ve bu fonksiyonda her bir veri için bir işlem yapılacak. Aslında bizim için önemli olan kısmın verisetinin ilk yüzde 10'luk kısmı olduğunu düşünelim. Sadece yüzde 10'luk bir kısım için tüm verisetinin işleme sokulmasına gerek yoktur. Tüm verisetinde işlem yapılması yerine, adım adım işlem yaptırabiliriz.
Generator tanımladığımızda bir fonksiyon sadece bizim söylediğimiz zaman çalışır ve birim zamanda bir işlem gerçekleşir. Peki fonksiyon bir işlem yaptı ve bir kez daha işlem yaptırmak istediğimizde, fonksiyon kaldığı yeri nereden bilecek? Burada devreye yield anahtar kelimesi giriyor. yield aslında return anahtar kelimesi gibidir. Fonksiyondan bir veriyi return eder ancak kaldığı yeri de hafızaya atar. Böylelikle bir sonraki adımda fonksiyonu çağırdığımızda kaldığı yeri hatırlar ve oradan bir işlem daha yapar. Şimdi bir örnek yapalım:


def calculate_sq():
    for i in range(1, 6):
        yield i ** 2


generator = calculate_sq()
iterator = iter(generator)

print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
>>
1
4
9
16
25
Burada 1'den başlayarak 6'ya kadar her sayının karesini alan bir fonksiyon tanımladık. Fonksiyonu bir değişkene eşitledik ve bu değişkeni iter() fonksiyonuna gönderdik. Bu iterator objesini, next() fonksiyonuna her gönderdiğimizde fonksiyon bir işlem yapacak ve yeni bir değer üretecektir.
Fonksiyonun işi bir anda değil de her komut verdiğimizde bir işlem yaparak bitirmesi lazy evulation olarak tanımlanır. Bir örnek daha yapalım:


list_1 = [i * 3 for i in range(5)]
print(list_1)

generator = (i * 3 for i in range(5))

iterator = iter(generator)

print(next(iterator))
print(next(iterator))
print(next(iterator))
>>
[0, 3, 6, 9, 12]
0
3
6
Bir örnek daha yapalım. Fibonacci sayılarını hesaplayan bir fonksiyon yazalım ve kullanalım:


def fibonacci():
    a = 1
    b = 1
    while True:
        a, b = b, a + b
        yield b


for num in fibonacci():
    if num > 100000:
        break
    print(num)
Burada fonksiyonda for döngüsü ile geziniyoruz, her bir iteration'da yield bizim için bir sayı üretecektir. Son bir örnek daha yapalım, asal sayı üreten bir generator fonksiyon tanımlayalım. Bu fonksiyon 2'den başlayacak ve her sayıyı bir sayının asal olup olmadığını kontrol eden bir fonksiyona gönderecek. Eğer bu fonksiyondan True değer dönerse yield ile sayıyı return edecek:


def is_prime(num):
    for i in range(2, num):
        if num % i == 0:
            return False
    return True


def prime_generator():
    i = 2
    while True:
        if is_prime(i):
            yield i
        i += 1


for next_num in prime_generator():
    if next_num > 100:
        break
    print(next_num)
>>
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97


Sonraki Yazı: Time Operations, datetime module
Yorumlar

Henüz bir yorum bulunmuyor.
Yorum bırakın