Giriş:
Python’da yield, return’e benzer bir şekilde çalışır. Herhangi bir programlama dilinde olduğu gibi, çalıştırılan bir metodun sonucunu döndürmek için return ifadesini kullanırız. Return ifadesi yalnızca metodun ürettiği değeri döndürür, Yield ise, çoklu sonuç içinden bir değer döndürüp bulunduğu noktayı hatırlayarak, sonraki çağrıda bulunduğu noktadan sonraki değeri döndürür. Return yerine python’da yield kullanılan fonksiyonlara generator fonksiyon denir ve birden fazla yield ifadesi barındırabilir. Bu şekilde bir fonksiyonun birden fazla sonuç döndürmesi sağlanabilir.
Bir metod, yield kelimesi içeriyorsa otomatik olarak bir generator fonksiyon haline gelir.
“Python’da yield”ın en çok kullanıldığı alan; bir “dizi” döndüren bir fonksiyonunuz varsa ve bu diziyi iterate edecekseniz, ama aynı zamanda dizideki her elemanın aynı anda bellekte bulunmasına gerek yoksa, bir generator fonksiyon ile bu dizinin iterate edilmesidir. Iterate yapılarak tüketilen bu generator fonksiyon, her bir değeri döndürdüğünde nerede kaldığını hatırlayarak sonraki iterasyonda kaldığı yerdeki değeri dönrürür ve tekrar çağırılmayı bekler.
Nasıl çalışır:
Yield ifadesi, sonuç döndürdüğünde metodun çalışmasını durdurur ve kaldığı yeri hatırlayarak sonraki iterasyonlarda yeniden çağrılan generator fonksiyondan değerleri birer birer döndürerek devam ettirir.
Örnek:
In [1]: def yield_function():
...: yield 10
...: yield 20
...: yield 30
In [2]: for y in yield_function():
...: print(y)
...:
10
20
30
next() ile kullanımı:
In [1]: def yield_func(l):
...: total = 0
...: for n in l:
...: yield total
...: total += n
In [2]: new_lst = yield_func([10, 20, 30])
In [3]: print(next(new_lst))
0
In [4]: print(next(new_lst))
10
In [5]: print(next(new_lst))
30
In [6]: print(next(new_lst))
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-9-b33a0da7654c> in <module>()
----> 1 print(next(new_lst))
StopIteration:
Neden Yield Kullanılmalı:
Iterate edilebilir generator fonksiyonlar yazmak için kullanmak gerek.
Zaten en önemli özelliği de bir fonksiyondan birden fazla sonuç almak gerektiği zamanlarda kullanımasıdır.
Sürekli çağrı yapılan generator fonksiyon, son kalınan yield statementinden itibaren çalışmaya başlayacaktır.
Böylece fonksiyon içindeki yield’a kadar olan tekrar çalıştırılmayrak CPU süresi kazanımı sağlar.
Generator fonksiyonlar veri akışlarıyla veya CSV dosyaları gibi büyük dosyalarla çalışılırken yaygın olarak kullanılmaktadır.
Örneğin:
import csv
def get_line_from(file_name):
with open(file_name, "r") as csv:
for line in csv.reader(f):
yield line
for line in get_line_from(file_name):
print(line)
Yukardaki örnekte tanımlanan get_line metodu ile bir dosyadaki her bir satırı yield ile almak suretiyle tüm dosyanın belleğe yüklenmesine gerek kalmadan satır satır okunması sağlanabilmekte.
Daha basit kullanımıyla:
def get_line_from(file_name):
for row in open(file_name, "r"):
yield row
Bir generator ifade yaratarak, en yalın haliyle şöyle de yazılabilir:
get_line_from = (row for row in open(file_name))
Dikkat ederseniz yukardaki örnekte köşeli parantez yerine “[” yerine düz parantez “(” kullandık. Eğer köşeli parantez kullanmış olsaydık, get_line_from, bir generator fonksiyon olmak yerine bir liste haline dönüşecekti. Ve belki de bu yüzden sistem belleğini tüketecekti. Single line generator ifade oluşturmak için görüldüğü üzere tuple içinde iterasyon yapıyoruz. Bu örnekte generator ifade içinde yield kullanmadığımızı da fark etmişsinizdir. Yield çıktısı, generator ifadelerin doğal özelliğidir.