Menu

Python Generator'lar: yield, Tembel İterasyon ve Generator İfadeleri

Python'da generator'lar değerleri nasıl tembel üretir — yield anahtar kelimesi, generator ifadeleri ve düz bir listeyi ne zaman geçerler.

Duraklayan Bir Fonksiyon

Bir generator normal bir fonksiyon gibi görünür ama tüm sonucu hesaplayıp döndürmek yerine değerleri birer birer yield eder, her yield'in arasında, soran kişi bir sonraki değeri isteyene kadar duraklar.

Mümkün olan en basit örnek:

main.py
Output
Click Run to see the output here.

return yerine yield'e dikkat et. for ilk değeri istediğinde Python fonksiyon gövdesini yield 1'e çarpana kadar çalıştırır. Fonksiyon tam orada duraklar, 1'i döngüye geri verir ve tam olarak nerede durduğunu — değişkenler dahil — hatırlar. Sonraki iterasyon, kaldığı yerden devam eder: current += 1, while'a dön, yield 2. Ve döngü koşulu başarısız olana kadar böyle gider; o noktada generator basitçe durur.

Bu durakla-devam et numarası, tüm işin sırrıdır.

Neden Sadece Bir Liste Kurmuyoruz?

Çünkü liste versiyonu tüm değerleri önceden ayırır:

main.py
Output
Click Run to see the output here.

5 öğe için uygun. Şimdi 50 milyon tamsayı istediğini ve yalnızca belirli bir koşulla eşleşen ilkini umursadığını hayal et. Liste versiyonu 50 milyon int ayırır ve sen çoğunu atarsın. Generator versiyonu, çağıranın tükettiği kadar üretir. for döngüsü istediğini bulup break yaptığında generator basitçe durur.

İçselleştirmeye değer kalıp şu: generator'lar, sonucun ne kadarını kullanacağına önceden karar vermeden iterasyon kodu yazmana izin verir.

Generator İfadeleri

Bir liste comprehension yazdıysan söz dizimini zaten biliyorsun — köşeli parantezleri parantezle değiştir:

main.py
Output
Click Run to see the output here.

squares_gen henüz hiçbir şey hesaplamaz. Sadece bir tariftir. Üzerinde gezmek, tarifi adım adım çalıştırır.

Generator ifadeleri, bir iterable tüketen fonksiyonlara argüman olarak mükemmeldir:

main.py
Output
Click Run to see the output here.

Ara liste yok. sum, max ve any, değerleri birer birer okur ki tam olarak istedikleri budur.

Büyük Bir Dosyayı Satır Satır Okumak

Bu, generator'ların kanonik gerçek dünya örneğidir — belleğe sığmayacak kadar büyük bir dosyayı işlemek:

def parse_log_lines(path):
    with open(path) as f:
        for line in f:
            if line.startswith("ERROR"):
                yield line.rstrip()

for error in parse_log_lines("app.log"):
    print(error)

Dosya tembel okunur. Generator'a her çağrı diskten bir satır çeker, filtreler ve yield eder. Dosya boyutundan bağımsız olarak bellek kullanımı sabit kalır.

Bir Kez ve Tamam

Bir generator'ın tek bir geçişi vardır. Sonuna kadar iterate ettikten sonra tükenir:

main.py
Output
Click Run to see the output here.

İkinci döngü hiçbir şey yazdırmaz. Generator'da bir şey kalmaz.

Birden fazla kez iterate etmen gerekirse, ya taze bir generator için fonksiyonu tekrar çağır ya da diziyi list(...) ile materyalize et ve listeyi tekrar tekrar iterate et. Maliyete göre seç: iş ucuzsa yeniden kurmak uygun; dizi küçükse liste uygun.

next() ve Manuel İterasyon

for döngüsü kullanmak zorunda değilsin. next() değerleri teker teker çeker:

main.py
Output
Click Run to see the output here.

StopIteration, bir generator'ın "işim bitti" sinyali vermesidir. for döngüleri onu sessizce yakalar. Manuel kodda istisnadan kaçınmak için next(gen, default)'a bir varsayılan geçebilirsin.

Sonsuz Generator'lar

Değerler talep üzerine üretildiği için, bir generator sonu olmayan bir diziyi temsil edebilir — tüketici sormayı bıraktığı sürece:

main.py
Output
Click Run to see the output here.

İçinde yield olan while True, programı asmaz — sadece "biri sormaya devam ederse üretmeye devam et" anlamına gelir. Tüketici ne zaman duracağına karar verir.

Bu kalıp, akış verisinde, olay döngülerinde ve tanımlı uzunluğu olmayan bir kaynaktan değer çektiğin her yerde görülür.

yield from: Başka Bir Iterable'a Devretmek

Generator'ın başka bir iterable'daki her değeri yield etmek istiyorsa, yield from bunu tek satırda yapar:

main.py
Output
Click Run to see the output here.

yield from olmadan içinde yield x olan iç içe bir for döngüsü yazardın. Ayrıca hiç kullanırsan send() ve throw() çağrılarını da doğru iletir — ama günlük kod için "bu şeydeki her değeri yield et" olarak düşün.

Generator'a Ne Zaman Uzanmalı

Bir generator'ın doğru araç olduğunu gösteren üç sinyal:

  1. Dizi büyük, belki sonsuz ya da tamamını üretmek pahalı.
  2. Tüketici sondan önce durabilir (örneğin, ilk eşleşmede break).
  3. Ara listeler kurmadan dönüşümleri zincirlemek istiyorsun — filtrele, eşle, al.

Ve ne zaman değil:

  • Rastgele erişime (seq[42]) ihtiyacın var. Generator'lar yalnızca ileri gider.
  • Aynı diziyi birkaç kez iterate etmen gerekir. Liste kullan.
  • Dizi küçük ve zaten elinde. Liste comprehension daha basittir.

Generator'lar, liste comprehension'lar ve düz listeler farklı işler için doğru cevaptır. Beceri, çok düşünmeden birini seçmektir — ve bu sezgiyi geliştirmenin en hızlı yolu, yazdığın her iterasyon için "önce her şeyi üret" mi yoksa "birer birer üret" mi daha iyi oturduğunu fark etmektir.

Sırada: Bağlam Yöneticileri Derinlemesine

Python'un iterasyon için kullandığı deyimlerin çoğunu artık gördün. Bağlam yöneticileri — with deyimi — sırada ve dosya ile ağ bağlantılarından veri akışı için generator'larla iyi eşleşir.

Sıkça Sorulan Sorular

Python'da generator nedir?

Generator, değerleri teker teker üreten ve aralarında duraklayan bir fonksiyondur. Normal bir fonksiyon gibi def ile yazarsın ama return yerine yield kullanırsın. Onu çağırmak bir generator nesnesi döndürür; her for iterasyonu ya da her next() çağrısı, bir sonraki yield'e kadar fonksiyonu çalıştırır.

Bir liste ile generator arasındaki fark nedir?

Bir liste her öğeyi aynı anda bellekte tutar. Bir generator öğeleri talep üzerine hesaplar ve tüketildikten sonra unutur. Büyük ya da sonsuz diziler için generator'lar küçük sabit bir bellek kullanır; tekrar tekrar ihtiyaç duyduğun küçük sonuçlar için liste daha iyidir.

Bir generator'ı iki kez iterate edebilir miyim?

Hayır. Bir generator, ilk tam geçişten sonra tükenir — üzerinde ikinci bir for döngüsü hiçbir şey üretmez. Birden fazla kez iterate etmen gerekirse, ya taze bir generator için fonksiyonu tekrar çağır ya da sonuçları bir listeye materyalize et.

Coddy ile kodlamayı öğren

BAŞLA