13.2. Generators

Generators, iterator yaratmanın basit bir yoludur. Bir generator, iteratif olabilecek bir nesneyi döndüren fonksiyondur. Basit örneklerle konuyu genişletelim.

 13.2.1. Bir generator yaratma

Python’da en kolay şekilde bir generator oluşturma return yerine yield ifadesini kullanmaktır. Eğer bir fonksiyon yield ifadesi içeriyorsa bir generator fonksiyonu haline dönüşür. Aslında bir fonksiyonda yield ve return ifadesi aynı değeri döndürür. Ancak, return ifadesi bir fonksiyonu sonlandırırken, yield ifadesi değeri döndürür, saklar ve fonksiyonu çağırma devam eder.

Bir örnek yapmadan önce normal bir fonksiyona göre farklılıkları sıralayalım:

  • Bir generator fonksiyonu bir veya birden fazla yield ifadesi içerebilir.
  • Çağrıldığı zaman, bir iterator nesnesi döndürür, ama işlemi hemen çalıştırma başlamaz.
  • __iter__() ve __next__() metotları otomatik olarak uygulanabilir.
  • Yield işlemi çağrıldığında kontrol duraklar ve çağrıya aktarılır.
  • Yerel değişkenler ve durumları ardışık çağrılarda unutulmaz.
  • Fonksiyon bittiğinde, StopIteration durumu tetiklenir.

Örneği inceleyip, yukarıdaki maddeleri tekrar okuyalım. i değeri her çağırma işleminde (next) yield bölümüne kadar fonksiyon çalışır. Burada duraklar ve yeni bir çağırma bekler. Yeni çağırmada tekrar çalışır. Durum kalmayıncaya kadar işlem devam eder. Ve durum kalmayınca bir StopIteration oluşur. Aynı işlemi for döngüsü ile yaparsak:

Çıktı olarak yukarıdaki çıktının aynısı oluşur.

 13.2.2. Döngü içeren generator

Şimdi yukarıdaki yield işlemini döngü ile tasarlayacağız. Bir string değişkenin tersini alan bir fonksiyon tasarlayalım.

range fonksiyonu en üst öğeden başlar ve -1 oluncaya kadar -1 azalır.

Bu fonksiyon sadece string için değil hem list hem de tuple için çalışır.

 13.2.3. Generator ifadesi

Generator ifadesi kullanarak genaratorler oluşturulabilir. Lambda ile isimsiz fonksiyonlar oluşturabildiği gibi generator ifadesi ile anonim bir generator fonksiyonu oluşturur. Generator sözdizimi list ifadesinin sözdizimine çok benzer, ama köşeli parantez yerine normal parantezler kullanılır. Bir list ifadesi ile bir generator ifadesi arasındaki hem önemli fark bir list ifadesi tam bir liste oluştururken genarator ifadesi bir seferde bir öğe oluşturur.  Bir generator ifadesi sadece istenildiğinde öğeyi oluşturur. Bu sebepten dolayı bir generator ifadesinin list ifadesine göre belleği çok daha etkin kullandığı söylenebilir.

Bu generator ifadesinin öğelerine ulaşmak için next metodu kullanılır. Örneğin,

StopIteration exception’ını oluştu.

Generator ile max, min, sum ve vb. fonksiyonlarda kullanılabilir. Örneğin,

 13.2.4. Generator niye kullanılır?

4 alt başlıkta bu konuyu işleyelim.

13.2.4.1. Uygulaması kolay

Generators iterator sınıfında olduğu gibi uygulaması kesin ve açıktır. Öncelikle iterator bölümünde anlattığımız küp alma sınıfını hatırlayalım.

Biraz uzun bir oldu, şimdi aynı işlemi generator kullanarak yapalım.

Örnekte olduğu generators uygulanması çok daha kolay ve daha az kodla yapılabilir. next() metodu ile yukarıdaki örnek dolaşabilir.

13.2.4.2. Bellek etkinliği

Bir liste döndürmek için normal bir fonksiyon, sonucu döndürmeden önce belleğe tüm diziyi oluşturur. Eğer liste çok büyükse bu diziyi tamamen belleğe yüklemek belleği aşırı şekilde kullanılmasına neden olabilir. Generator ise bellek dostu olup bir seferde sadece bir öğe ürettiği için tercih edilir.

13.2.4.3. Sonsuz bir veri akışı sunar

Generator, sonsuz bir veri akışını temsil etmek için mükemmel bir ortamdır. Sonsuz akışlar bellekte saklanamaz ve bir generator bir seferde yalnızca bir öğe ürettiğinden, sonsuz veri akışını temsil edebilir. Aşağıdaki örnek tüm çift sayıları oluşturabilir (en azından teoride, sonuçta adım adım ulaştığımızı unutmayalım).

13.2.4.4. Generator ile pipeline

Generator, bir dizi işlemi sıraya koyup işelemek (pipeline) için kullanılabilir. Örneğin, bir restoranın bir log dosyasına sahip olalım. Bu dosya, her saatte satılan pizza sayısını 2. kolonda tutsun ve 5 yıl içinde toplam pizza sayısını bulmak için aşağıdaki gibi bir generator uygulaması yazılabilir.

Bu pipeline işlemi hazırlaması kolay ve etkindir.