Python’da yield ne işe yarar?

Python’da yield kelimesinin ne işe yaradığını anlamak için önce generatorlerin ne olduğunu anlamalıyız.

İlişkili olduğu konular : how to, nasıl

Python’da yield kelimesinin ne işe yaradığını anlamak için önce generatorlerin ne olduğunu anlamalıyız. Ve generatorleri anlamadan önce, yinelemeleri anlamalısınız. Ancak, bunları öğrenmeden önce yield’a hızlı bir bakış atalım.

return komutunu öğrendiğinizi varsayıyoruz.

Bir benzetme olarak, return ve yield‘ı birbirinin ikizi gibi düşünebiliriz. return ‘döndür ve durdur’ anlamına gelirken , ‘yield‘ ‘döndür, ancak devam et’ anlamına gelir:

  1. num_list’i return ile döndürmeye çalışalım
def num_list(n):
    for i in range(n):
        return i

Çıktı:

In [5]: num_list(3)
Out[5]: 0

Bir liste yerine sadece tek bir sayı döndürdük. return benzer bir kodda asla mutlu bir şekilde ayrılmamıza izin vermiyor, sadece bir kez uygulanıyor ve bitiyor.

  1. yield‘a bakalım:

return‘ü yield ile değiştirelim

In [10]: def num_list(n):
    ...:     for i in range(n):
    ...:         yield i
    ...:

In [11]: num_list(3)
Out[11]: <generator object num_list at 0x10327c990>

In [12]: list(num_list(3))
Out[12]: [0, 1, 2]

Şimdi tüm sayıları alabildik.

return bir kez çalışır ve durur, ancak, yield planladığınız zamanlarda çalışır. return‘ü “bunlar arasından birini döndür” olarak yorumlayabiliriz. Diğer taraftan yield‘ı “bunların hepsini döndür” olarak yorumlayabiliriz.

  1. return ifadesini yeniden aşağıdaki gibi yazalım
In [15]: def num_list(n):
    ...:     result = []
    ...:     for i in range(n):
    ...:         result.append(i)
    ...:     return result

In [16]: num_list(3)
Out[16]: [0, 1, 2]

Burada ise return bir liste döndürdü. Buna karşın yield kullandığımızda bir generator elde ettik.

Şimdi daha yield’a daha detaylı bakalım:

Yinelemeler nedir?

Bir liste oluşturduğunuzda öğelerini tek tek okuyabilirsiniz. Öğelerini tek tek okumak yineleme olarak adlandırılır:

>>> listem = [1, 2, 3]
>>> for i in listem:
...    print(i)

1
2
3

listem bir yinelenebilirdir. Bir list comprehension oluşturduğunuzda ise, hem bir liste oluşturursunuz ve hem de yinelenebilir:

>>> listem = [x*x for x in range(3)]
>>> for i in listem:
...    print(i)

0
1
4

"for … in …" şeklinde kullanabileceğiniz her şey yinelenebilirdir; listeler, dizeler, dosyalar …

Yineleme öğelerinden istediğimiz kadar kullanabiliriz. Dolayısıyla bunlar oldukça kullanışlılar. Ancak tüm değerleri bellekte saklarsak ve çok fazla değerimiz varsa kullanışlı olmayabilirler.

Generator nedir?

Generatorler yineleyicilerdir. Ancak bu yineleyiciler özel bir türdür ve yalnızca bir kez yinelenebilir. Generatorler değerleri bellekte saklamazlar ve kullanılacakları zaman üretirler (on-the-fly):

>>> generatorum = (x*x for x in range(3))
>>> for i in generatorum:
...    print(i)

0
1
4

[] yerine () kullanmamız dışında her şey aynı. AMA, generatorler sadece bir kez kullanılabildiklerinden, for i in generatorum kalıbını ikinci kez kullanamayız: 0’ı hesaplarlar, sonra unuturlar. 1’i hesaplarlar, 4’ü hesaplarlar ve işlemi bitirirler.

yield nedir?

yield, return gibi kullanılan bir anahtar kelimedir. Ancak, yield kullanıldığında fonksiyon bir generator döndürür.

>>> def generator_olustur():
...    listem = range(3)
...    for i in listem:
...        yield i*i
...
>>> generatorum = generator_olustur() # generator olusturalım
>>> print(generatorum) # generatorum bir nesne!
<generator object generator_olustur at 0xb7555c34>
>>> for i in generatorum:
...     print(i)
0
1
4

Bu örnek çok kullanılışlı görünmeyebilir. Ancak fonksiyonunuzun yalnızca bir kez okumanız gereken çok fazla elemanlı bir değer kümesi döndüreceğini bildiğinizde kullanışlı olacaktır.

yield konusunda ustalaşmak için fonksiyonu çağırdığınızda, fonksiyon gövdesine yazdığınız kodun çalışmadığını anlamalısınız. Fonksiyon yalnızca generator nesnesini döndürür. Bu kısım biraz karmaşık.

Kod bu şekilde generatorü her kullandığınızda kaldığı yerden devam edecektir.

Şimdi işin zor kısmı:

for fonksiyonunuzda oluşturulan generator nesneyi ilk kez çağırdığında, fonksiyondaki kodu baştan yielda ulaşana kadar çalıştırır. Ardından döngünün ilk değerini döndürür. Fonksiyona yapılan sonraki her çağrı fonksiyonda yazdığınız döngünün başka bir yinelemesini çalıştırır ve dolayısıyla bir sonraki değeri döndürür. Bu, generator boş kabul edilene kadar devam edecektir.

yield nasıl çalışır?

yield, yineleyici protokolü uygulamanın kolay bir yolunu sağlar. Bunu __iter__ ve __next__ (Python 2) veya __next__ (Python 3) metotları ile gerçekleştirir.

>>> def func():
...     yield 'Ben'
...     yield 'bir generatorum!'
... 
>>> type(func)                 # yield olan bir fonksiyon yine de bir fonksiyondur
<type 'function'>
>>> gen = func()
>>> type(gen)                  # ama generator döndürür
<type 'generator'>
>>> hasattr(gen, '__iter__')   # yinelenebilirdir
True
>>> hasattr(gen, 'next')       # ve .next (.__next__ in Python 3) ile
True                           # iterator protokolünü çalıştırır

Sade bir dille anlatmak gerekirse;

Bir dizi sayı üzerinde işlem yapmak istiyorum, ancak bu dizinin yaratılmasıyla uğraşmak istemiyorum. Sadece yapmak istediğim işleme odaklanmak istiyorum. Bu yüzden aşağıdakileri yapıyorum:

Sizi arayıp belirli bir şekilde üretilmiş bir dizi sayı istediğimi söylüyorum ve algoritmanın ne olduğunu da söylüyorum.
Bu adım, generator fonksiyonunun, yani yield içeren fonksiyonun tanımlanmasına karşılık geldi.

Bir süre sonra sana “Tamam, bana sayıların sırasını anlatmaya hazır ol” diyorum.

Bu adım, bir generator nesnesi döndüren generator fonksiyonu çağırmaya karşılık geldi. Henüz bana bir sayı söylemediniz; sadece kağıt ve kaleminizi aldınız.

Şimdi size, “bana bir sonraki numarayı söyleyin” diyorum ve siz bana ilk numarayı söylüyorsunuz. Ondan sonra, benden bir sonraki numarayı sormamı bekliyorsunuz. Nerede olduğunuzu, hangi sayıları söylediğinizi ve bir sonraki sayının ne olduğunu hatırlamak sizin işiniz. Detaylar benim için önemli değil.

Bu adım, generator nesnesinde .next()‘i çağırmaya karşılık geldi.
Buraya kadar önceki adımları tekrar ettik ve sona geldik. Burada artık bana “başka sayı yok!” diyorsunuz.

Bu adım, generator nesnenin işini bitirmesine ve bir StopIteration istisnasının fırlatılmasına karşılık geldi. Generator fonksiyonunun istisnayı oluşturması gerekmez. Fonksiyon sona erdiğinde veya bir dönüt verdiğinde otomatik olarak fırlatılır.

Dolayısıyla generatorun yaptığı şey şöyledir; yürütmeye başlar, bir ürün verdiğinde duraklar ve bir .next() değeri sorulduğunda son noktadan devam eder. Python’un yineleyici protokolü ile de tasarımı gereği mükemmel uyum sağlar.

>>> def f():
...   yield 1
...   yield 2
...   yield 3
... 
>>> g = f()
>>> for i in g:
...   print(i)
... 
1
2
3
>>> for i in g:
...   print(i)
... 
>>> # Artık yazdıracak bir şey kalmadı
Bu yazı topluluk tarafından oluşturuldu. Lisans bilgisine bakabilirsiniz. Yanlış veya eksik bilgileri düzenlemek için github üzerinden katkıda bulunabilirsiniz.

Kategoriler: Yazı, Python

Okumaya devam et!

Python101 – 10’a kadar say

Döngüler İlk kontrol yapımıza geçiyoruz.

Python programının yürütülmesi için geçen süreyi nasıl ölçeriz?

Diyelimki Python’da çalışması biraz zaman alan bir komut satırı programım var.

Python’da Program Oluşturma ve Çalıştırma

Python ile ilk programımızı oluşturalım.

Python’da dizeyi sıfırla doldurma

Sayısal dizenin belirli bir uzunluğa sahip olması için, sayısal bir dizeyi solda sıfırlarla doldurmanın en pythonik yolu nedir? str.

Yorum Gönderin

E-posta hesabınız yayımlanmayacak.

koddla
Tema Mundana by WowThemes.net.