Bu derste Pythondaki generatorları anlamaya çalışacağız.
Generatorlar Pythonda iterable objeler (örnek olarak fonksiyonlar) oluşturmak için kullanılan objelerdir ve bellekte herhangi bir yer kaplamazlar. Örneğin, 100.000 tane değer üretip, bu değerleri bir listede tutmak bellekte oldukça fazla yer kaplayacaktır. O yüzden bu işlemi gerçekleştiren bir fonksiyonu generator fonksiyon şeklinde yazmak oldukça mantıklı olacaktır. Generatorları anlamak için isterseniz bir fonksiyonu ilk olarak generator kullanmadan yazmaya çalışalım.
def karelerial():
sonuç = []
for i in range(1,6):
sonuç.append(i**2)
return sonuç
print(karelerial())
[1, 4, 9, 16, 25]
İsterseniz bu fonksiyonu bir de generator kullanarak yazmaya çalışalım. Generatorlerin değer üretmesi için yield anahtar kelimesini kullanacağız.
def karelerial():
for i in range(1,6):
yield i ** 2 # yield anahtar kelimesi generator'un değer üretmesi için kullanılıyor.
generator = karelerial()
print(generator) # Generator objesi
<generator object karelerial at 0x0000009441354DB0>
Yazdığımız ilk fonksiyonda 1'den 6'ya kadar gidip her bir değerin karesini sonuç isimli listeye atıyoruz ve daha sonra bu listeyi dönüyoruz.Yani bellekte liste değişkenin içinde 1,4,9,16,25 değerleri tutuluyor.
Generatorle yazdığımız 2.fonksiyonda yield anahtar kelimesiyle değerleri ürettiğimizi sanıyoruz. Ama aslında bu fonksiyonu çağırınca bize sadece bir tane generator objesi dönüyor ve biz sadece generator objesinin değerlerine ulaşmaya çalıştığımızda değerler tek tek üretiliyor. Yani kısacası bellekte değerler tutulmuyor. Bu generator objesinin üzerinde bir tane iterator oluşturarak durumu daha iyi anlamaya çalışalım.
iterator = iter(generator)
print(next(iterator)) # 1 değeri üretildi
print(next(iterator)) # 4 değeri üretildi 1 değeri tarihe karıştı.
print(next(iterator)) # 9 değeri üretildi 4 değeri tarihe karıştı.
print(next(iterator)) # 16 değeri üretildi 9 değeri tarihe karıştı
print(next(iterator)) # 25 değeri üretildi 16 değeri tarihe karıştı.
print(next(iterator)) # Üretilecek değer kalmadı.
1 4 9 16 25
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-9-dd39ed4db3a3> in <module>() 6 print(next(iterator)) 7 print(next(iterator)) ----> 8 print(next(iterator)) StopIteration:
Aslında generator objesi sadece değerlere ulaşmak istediğimiz zaman yield anahtar kelimesini kullanıp değer üretiyor. Yani generatorler sadece biz değerlere ulaşmak istersek çalışıyor. İşte generatorlerin mantığı tamamıyla bu şekilde ! Şimdi de list comprehensionları generatorlara çevirmeye çalışalım.
liste = [i * 3 for i in range(5)]
liste
[0, 3, 6, 9, 12]
Böyle bir list comprehension'ı generator objesine çevirmek için [] yerine () kullanıyoruz.
generator = (i * 3 for i in range(5))
print(generator)
<generator object <genexpr> at 0x0000009441374990>
iterator = iter(generator)
print(next(iterator))
0
print(next(iterator))
3
print(next(iterator))
6
print(next(iterator))
9
print(next(iterator))
12
print(next(iterator))
--------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-32-369d18de2e56> in <module>() ----> 1 print(next(iterator)) StopIteration:
İsterseniz konuyu anlamak için bir tane daha generator fonksiyonu oluşturalım.
def carpimtablosu():
for i in range(1,11):
for j in range(1,11):
yield "{} x {} = {}".format(i,j,i*j)
for i in carpimtablosu():
print(i)
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 1 x 4 = 4 1 x 5 = 5 1 x 6 = 6 1 x 7 = 7 1 x 8 = 8 1 x 9 = 9 1 x 10 = 10 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 2 x 4 = 8 2 x 5 = 10 2 x 6 = 12 2 x 7 = 14 2 x 8 = 16 2 x 9 = 18 2 x 10 = 20 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9 3 x 4 = 12 3 x 5 = 15 3 x 6 = 18 3 x 7 = 21 3 x 8 = 24 3 x 9 = 27 3 x 10 = 30 4 x 1 = 4 4 x 2 = 8 4 x 3 = 12 4 x 4 = 16 4 x 5 = 20 4 x 6 = 24 4 x 7 = 28 4 x 8 = 32 4 x 9 = 36 4 x 10 = 40 5 x 1 = 5 5 x 2 = 10 5 x 3 = 15 5 x 4 = 20 5 x 5 = 25 5 x 6 = 30 5 x 7 = 35 5 x 8 = 40 5 x 9 = 45 5 x 10 = 50 6 x 1 = 6 6 x 2 = 12 6 x 3 = 18 6 x 4 = 24 6 x 5 = 30 6 x 6 = 36 6 x 7 = 42 6 x 8 = 48 6 x 9 = 54 6 x 10 = 60 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 7 x 10 = 70 8 x 1 = 8 8 x 2 = 16 8 x 3 = 24 8 x 4 = 32 8 x 5 = 40 8 x 6 = 48 8 x 7 = 56 8 x 8 = 64 8 x 9 = 72 8 x 10 = 80 9 x 1 = 9 9 x 2 = 18 9 x 3 = 27 9 x 4 = 36 9 x 5 = 45 9 x 6 = 54 9 x 7 = 63 9 x 8 = 72 9 x 9 = 81 9 x 10 = 90 10 x 1 = 10 10 x 2 = 20 10 x 3 = 30 10 x 4 = 40 10 x 5 = 50 10 x 6 = 60 10 x 7 = 70 10 x 8 = 80 10 x 9 = 90 10 x 10 = 100
Buradaki bu kadar işlemi listelerde tutmak o kadar mantıklı değil. Onun yerine bellekte yer kaplamayan ve sadece her ulaşmaya çalıştığımızda değer üreten(yield) generator fonksiyonları kullanmak daha mantıklı olacaktır.
Peki generatorlar Pythonda nerede kullanılıyor ? Aslında bizim daha önce öğrendiğimiz range fonksiyonu Pythonda generatorlar yazılmış bir fonksiyondur.
for i in range(100): # Sadece istediğimiz zaman sayılara ulaşıyoruz.
print(i)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
İşte generatorların genel mantığı bu şekilde. Anlamadığınız bir yer olursa lütfen çekinmeden sorun. Bir sonraki derste görüşmek üzere.