---
title: Üreteçler
source: 'https://academia.sh/tr/kurslar/python-veri-yapilari/uretecler'
course: 'Veri Yapıları ve Fonksiyonel Araçlar'
language: tr
updated: '2026-08-17T18:10:26+00:00'
license: 'CC BY-SA 4.0'
---

# Üreteçler

Üreteç işlevini çağırmak gövdesinden tek satır çalıştırmaz: bin öğelik iş kavramada kurulumda 1000 nesne var ederken üreteçte 0 var eder ve üç öğe istendiğinde 3'te kalır.

Önceki ders yineleyici sözleşmesini ölçtü ve onu elle yazan bir sınıf kurdu: `Sayim` beş
satırda iki özel yöntem, bir sınır ve bir konum alanı istedi. Hepsi tek bir iş içindi —
nerede kalındığını hatırlamak. O iş her yineleyicide tekrarlanır ve konum tek bir sayı
olmadığında sınıf hızla büyür. İç içe bir gezinti için birden çok sayaç, dallanmış bir
arama için bir yığıt gerekir; her biri elle taşınmalıdır.

Oysa sıradan bir işlev bu bilgiyi zaten taşır. Bir işlev çalışırken hangi satırda olduğu,
yerel adlarının hangi değerlere bağlı olduğu bellidir; yalnız işlev bittiğinde hepsi
kaybolur. Bu dersin sorusu şudur: işlev **bitmek yerine duraklayabilseydi**, konumu ayrıca
yazmaya gerek kalır mıydı? Python'un yanıtı **üreteç (generator)** işlevidir ve ölçülecek
sayı şudur — böyle bir işlevi çağırmak, gövdesindeki bin üretimden kaçını çağrı anında
yapar?

## Duraklayan İşlev

Bir işlev gövdesinde `return` yerine `yield` geçiyorsa o işlev artık sıradan bir işlev
değildir. Çağrıldığında gövdesi çalışmaz; geriye bir **üreteç nesnesi** döner. Gövde ancak
o nesneden bir öğe istendiğinde çalışmaya başlar ve ilk `yield` deyimine gelince **durur**.
Durduğu yerde yerel adlar, döngü sayaçları ve çağrı çerçevesi olduğu gibi kalır. Bir sonraki
istek geldiğinde yürütme `yield`'in hemen ardından devam eder.

Ayrım burada nettir: `return` çerçeveyi yıkar, `yield` **askıya alır**. Programlama
Temelleri kursu tembel değerlendirmeyi bir paradigma tercihi olarak tanıtmıştı — değerin
kullanıldığı ana kadar hesaplanmaması. Burada ölçülen şey o tercihin adı değil, Python'un
onu hangi düzenekle verdiği ve **kaç nesneye mal olduğudur**.

## Üreteç Bir Yineleyicidir

Üreteç nesnesi önceki dersin sözleşmesini imzalar: `__iter__` ve `__next__` tanımlıdır,
`__iter__` kendisini döndürür, gövde bittiğinde `StopIteration` fırlatılır. Yani üreteç,
`Sayim` sınıfının elle yazdığı şeyin dil tarafından yazılmış hâlidir — sözleşmenin **yazan
tarafı**, ama sınıf kurmadan.

Buradan iki sonuç doğrudan gelir. Üreteç **tek geçişliktir**, çünkü `__iter__` kendisini
döndürür. Ve tükendikten sonra yenilenmez, çünkü gövdesi sona ulaşmıştır. İkisi de önceki
derste sözleşmenin sonucu olarak kurulmuştu; burada bir kez daha ölçülür.

Ölçümün varsayımları:

- **YN10** — Ortak tanımın `Oge` sınıfı ve `N = 1000` sayısı aynen kullanılır; sayma düzeni
  değiştirilmez.
- **YN11** — Üç biçim de **aynı** işi tanımlar: bin öğelik bir akış. Değişen tek şey
  yazımdır; kâhin kurgunun kendisidir, çünkü üretimi nesne kendi sayar.
- **YN12** — "Kurulumda" ölçümü, biçimin yazıldığı satır çalıştıktan hemen sonra alınır.
  "Üç öğe sonra" ölçümü, üç öğe istendikten sonra alınır; kavramada bu istek `liste[:3]`
  ile yapılır, öbür ikisinde `next` ile.
- **YN13** — İz kaydı gövdenin içine yerleştirilmiş bir listedir; her satır hangi noktaya
  ulaşıldığını yazar. "Gövde çalıştı mı" sorusunun ölçüsü bu listedir.
- **YN14** — İz ölçümünde öğe sayısı üçtür; ölçülen şey sayı değil, çağrı ile gövdenin
  ilerlemesi arasındaki ilişkidir.
- **YN15** — Sonsuz üreteç ölçümü kasıtlıdır: kurulumun sıfır üretmesi, öğe sayısının sonlu
  olmasından gelmiyor.
- **YN16** — Birleştirme ölçümünde iki kanat **400** ve **600** öğelidir; toplam yine
  **1000**'dir ve üç biçim aynı öğe dizisini verir.
- **YN17** — "İlk öğeye dek" sütunu, birleşimden yalnız bir öğe alındıktan sonraki üretim
  sayısıdır; biçimler arasındaki farkı bu sütun ayırır.
- **YN18** — Kapanış ölçümünde akış bin öğeliktir ama üç öğe alındıktan sonra `close` ile
  bırakılır; `finally` bloğuna konan iz satırı o anki üretim sayısını da yazar, böylece
  kapanışın ne zaman çalıştığı ölçülebilir.

## Ölçüm

```python
"""Uretec: govde ne zaman calisir, kurulum kac nesne var eder."""

SAYAC = {"uretilen": 0}
IZ = []


class Oge:
    """Her uretimi sayan oge."""

    def __init__(self, deger):
        SAYAC["uretilen"] += 1
        self.deger = deger

    def __repr__(self):
        return f"Oge({self.deger})"


def sifirla():
    SAYAC["uretilen"] = 0


def uretilen():
    return SAYAC["uretilen"]


N = 1000


def uretec_islevi(n=N):
    for i in range(n):
        yield Oge(i)


def kavrama(n=N):
    sifirla()
    liste = [Oge(i) for i in range(n)]
    kurulumda = uretilen()
    ilk_uc = liste[:3]
    return kurulumda, uretilen(), len(ilk_uc)


def uretec_ifadesi(n=N):
    sifirla()
    akis = (Oge(i) for i in range(n))
    kurulumda = uretilen()
    ilk_uc = [next(akis) for _ in range(3)]
    return kurulumda, uretilen(), len(ilk_uc)


def uretec_cagrisi(n=N):
    sifirla()
    akis = uretec_islevi(n)
    kurulumda = uretilen()
    ilk_uc = [next(akis) for _ in range(3)]
    return kurulumda, uretilen(), len(ilk_uc)


print(f"{'biçim':<24s} {'kurulumda':>10s} {'üç öğe sonra':>13s} {'elde':>5s}")
for ad, f in (("kavrama", kavrama), ("üreteç ifadesi", uretec_ifadesi),
              ("üreteç işlevi çağrısı", uretec_cagrisi)):
    a, b, c = f()
    print(f"  {ad:<22s} {a:10d} {b:13d} {c:5d}")


def izli(n=3):
    IZ.append("gövde başladı")
    for i in range(n):
        IZ.append(f"yield {i} öncesi")
        yield Oge(i)
        IZ.append(f"yield {i} sonrası")
    IZ.append("gövde bitti")
    return "son"


IZ.clear()
g = izli()
print()
print(f"çağrıdan sonra iz: {IZ}")
next(g)
print(f"birinci next sonrası: {IZ}")
next(g)
print(f"ikinci next sonrası: {IZ}")
print(f"üreteç yineleyici mi: iter(g) is g -> {iter(g) is g}")

IZ.clear()
son = izli(1)
next(son)
try:
    next(son)
except StopIteration as e:
    print(f"gövde bittiğinde: {IZ[-1]!r}, istisnanın taşıdığı değer {e.value!r}")

tek = uretec_islevi(3)
print()
print(f"üreteç işlevi tek geçişlik: {len(list(tek))} ve {len(list(tek))} öğe")


def sonsuz():
    i = 0
    while True:
        yield Oge(i)
        i += 1


sifirla()
akis = sonsuz()
kurulum = uretilen()
[next(akis) for _ in range(3)]
print(f"sonsuz üreteç: kurulumda {kurulum}, üç öğe istendiğinde {uretilen()}")


def kanat(a, b):
    yield from uretec_islevi(a)
    yield from uretec_islevi(b)


def elle_kanat(a, b):
    for o in uretec_islevi(a):
        yield o
    for o in uretec_islevi(b):
        yield o


def ara_liste(a, b):
    return list(uretec_islevi(a)) + list(uretec_islevi(b))


print()
print(f"{'birleştirme biçimi':<22s} {'kurulumda':>10s} {'ilk öğeye dek':>14s}"
      f" {'tümü gezilince':>15s}")
for ad, f in (("yield from", kanat), ("iç içe for + yield", elle_kanat),
              ("iki listeyi ekleme", ara_liste)):
    sifirla()
    n = f(400, 600)
    kurulumda = uretilen()
    y = iter(n)
    next(y)
    ilk = uretilen()
    list(y)
    print(f"  {ad:<20s} {kurulumda:10d} {ilk:14d} {uretilen():15d}")


def toplayici():
    toplam = 0
    try:
        while True:
            gelen = yield toplam
            toplam += gelen
    finally:
        IZ.append("toplayıcı kapandı")


def kaynak(n=N):
    try:
        for i in range(n):
            yield Oge(i)
    finally:
        IZ.append(f"kaynak kapandı, o ana dek üretilen {uretilen()}")


IZ.clear()
t = toplayici()
ilk = next(t)
print()
print(f"yield bir ifadedir: ilk değer {ilk}, send(5) -> {t.send(5)},"
      f" send(7) -> {t.send(7)}")
t.close()
print(f"close çağrısından sonra iz: {IZ}")

IZ.clear()
sifirla()
akis = kaynak()
uc = [next(akis) for _ in range(3)]
akis.close()
print(f"bin öğelik akıştan üç öğe alınıp bırakıldı: elde {len(uc)},"
      f" üretilen {uretilen()}")
print(f"kapanış izi: {IZ}")
```

```
biçim                     kurulumda  üç öğe sonra  elde
  kavrama                      1000          1000     3
  üreteç ifadesi                  0             3     3
  üreteç işlevi çağrısı           0             3     3

çağrıdan sonra iz: []
birinci next sonrası: ['gövde başladı', 'yield 0 öncesi']
ikinci next sonrası: ['gövde başladı', 'yield 0 öncesi', 'yield 0 sonrası', 'yield 1 öncesi']
üreteç yineleyici mi: iter(g) is g -> True
gövde bittiğinde: 'gövde bitti', istisnanın taşıdığı değer 'son'

üreteç işlevi tek geçişlik: 3 ve 0 öğe
sonsuz üreteç: kurulumda 0, üç öğe istendiğinde 3

birleştirme biçimi      kurulumda  ilk öğeye dek  tümü gezilince
  yield from                    0              1            1000
  iç içe for + yield            0              1            1000
  iki listeyi ekleme         1000           1000            1000

yield bir ifadedir: ilk değer 0, send(5) -> 5, send(7) -> 12
close çağrısından sonra iz: ['toplayıcı kapandı']
bin öğelik akıştan üç öğe alınıp bırakıldı: elde 3, üretilen 3
kapanış izi: ['kaynak kapandı, o ana dek üretilen 3']
```

## Kurulumun Bedeli

Üst tablo ortak tanımın ikinci iddiasının ilk yarısıdır ve üç satır aynı işi tanımlar: bin
öğelik bir akış.

**Kavrama** daha yazıldığı satırda **1000** nesne var ediyor. Üç öğe istendiğinde sayı
değişmiyor — çünkü zaten hepsi üretilmişti; `liste[:3]` yalnız var olanlardan üçünü
gösteriyor.

**Üreteç ifadesi** ve **üreteç işlevi çağrısı** kurulumda **0** var ediyor. Üç öğe
istendiğinde **3**'e çıkıyor. Aradaki 997 nesne hiç doğmuyor, çünkü kimse istemedi.

İki sayı arasındaki uçurum yazımda görünmez. Üç satırın üçü de tek bir deyimdir, üçü de bin
öğelik bir akışı adlandırır, üçü de sonrasında `for` döngüsüne sokulabilir. Kurulumun
**1000** mi **0** mı olduğunu söyleyen tek şey köşeli ayraç ile parantez arasındaki fark ve
`yield` anahtar sözcüğüdür.

Buradaki tembelliğin sınırını doğru okumak gerekir. **0**, işin yapılmadığı anlamına gelmez;
**henüz** yapılmadığı anlamına gelir. Üç öğe istendiğinde üç nesne doğuyor; bin öğe
istenirse bin nesne doğacak. Bu dersin ölçtüğü sayı yalnız **ne zaman** sorusunun yanıtıdır;
**toplamda kaç** sorusunun yanıtı bir sonraki dersin konusudur.

`üreteç ifadesi` satırının yazımı — köşeli ayraç yerine parantez — bu dersin konusu
değildir; sonraki ders onu kendi başına ölçer. Burada yalnız kurulum sayısını vermek için
tabloda duruyor.

## Gövde Nerede Duruyor

Orta blok gövdenin ilerleyişini iz kaydıyla gösteriyor ve ilk satır en şaşırtıcı olanıdır:
üreteç işlevi çağrıldıktan sonra iz **boş**. Gövdeden tek satır çalışmamış. Çağrı bir işi
başlatmamış, bir **nesne kurmuş**.

Birinci `next` çağrısından sonra iz iki satır: gövde başladı ve ilk `yield`'e kadar geldi.
Orada durdu. İkinci çağrıdan sonra iki satır daha eklendi — yürütme `yield`'in **ardından**
devam etti, döngünün bir sonraki turuna geçti ve ikinci `yield`'de yine durdu. Yerel `i`
adı iki çağrı arasında korundu; kimse onu bir yere yazmadı, çerçeve olduğu gibi askıda
bekledi.

Bu, `Sayim` sınıfının elle yaptığı işin tam karşılığıdır. Orada konum bir öznitelikti ve her
çağrıda elle ilerletiliyordu; burada konum **gövdenin kendisidir** ve dil onu koruyor.
`iter(g) is g` satırı sözleşmenin öbür ucunu doğruluyor: üreteç kendi yineleyicisidir. Tek
geçişlilik de aynı yerden geliyor — `3` ve `0`.

## Bitişin Taşıdığı Değer

Gövde sona ulaştığında iz son satırını yazıyor ve `StopIteration` doğuyor. İlginç olan
istisnanın **boş olmaması**: `return "son"` deyiminin değeri istisnanın üzerinde taşınıyor.

Bu, `return` ile `yield`'in bir üreteçte nasıl bölüştüğünü gösterir. `yield` akışın
öğelerini verir; `return` akışın **sonucunu** verir ve akışın parçası değildir. Bir üreteci
`for` ile gezen taraf bu değeri hiç görmez, çünkü döngü `StopIteration`'ı yakalayıp atar.
Değeri isteyen tarafın istisnayı kendisi yakalaması gerekir.

Sonsuz üreteç satırı tembelliğin sonluluğa bağlı olmadığını gösteriyor: gövdesi hiç bitmeyen
bir döngü olan üreteç kurulumda yine **0** var ediyor ve üç öğe istendiğinde **3**'te
kalıyor. Böyle bir akışı kavramayla yazmak olanaksızdır — kavrama bitmeyen bir kaynağı
tüketmeye çalışır ve hiçbir zaman ilk satırdan çıkmaz. Tembellik burada bir eniyileme değil,
**ifade edilebilirlik** koşuludur.

## Yetki Devri

Son tablo iki akışı birleştirmenin üç yolunu ölçüyor ve üçü de aynı **1000** öğeyi veriyor.

`yield from` bir üreteci başka bir üretecin öğelerini teslim etmekle görevlendirir: dış
üreteç kendi gövdesini askıya alır ve istekleri iç üretece devreder. Kurulumda **0**, ilk
öğe alındığında **1**. `for` döngüsüyle elle yazılan biçim aynı sayıları veriyor;
`yield from` bu döngünün kısaltmasıdır ve iç üretecin bitiş değerini de aktarır.

**İki listeyi ekleme** satırı ayrılıyor. Kurulumda **1000** — çünkü `list()` çağrıları iki
kanadı da sonuna kadar tüketiyor. İlk öğeye ulaşmadan önce bin nesne doğmuş ve iki ara liste
kurulmuş oluyor; üstelik `+` işleci üçüncü bir liste daha üretir. Sonuç aynı, sıra aynı,
öğeler aynı; ayrılan tek şey ilk öğenin **kaç üretimden sonra** geldiğidir.

Ölçüm bir zincirin nerede kırıldığını da söyler: tembel bir akışa tek bir `list()` çağrısı
girdiğinde zincirin o noktasında tembellik biter. Sonraki halkalar tembel yazılmış olsa bile
kendilerinden önceki bin üretimi geri alamaz.

## Kanalın İki Yönü ve Kapanış

Son dört satır `yield`'in tek yönlü bir çıkış olmadığını gösteriyor. `yield` bir deyim
değil bir **ifadedir** ve bir değere sahiptir: askıdaki üreteç `send` ile uyandırıldığında,
duran `yield` ifadesi gönderilen değeri döndürür ve gövde oradan devam eder. Ölçümdeki
toplayıcı `send(5)` ile **5**, `send(7)` ile **12** veriyor; toplam iki çağrı arasında
gövdenin yerel adında duruyor.

İlk `next` çağrısı bu düzende zorunludur: gövde henüz ilk `yield`'e ulaşmamışsa gönderilen
değeri alacak bir ifade yoktur. Bu yüzden `send` ile beslenen her üreteç önce bir kez
ilerletilir; ölçümdeki **0** o ilk `yield`'in verdiği başlangıç değeridir.

Son iki satır tembel akışların en kolay atlanan yanını ölçüyor. Bin öğelik akıştan üç öğe
alınıp akış bırakıldığında üretilen **3**'te kalıyor — buraya kadar beklenen. Beklenmedik
olan `finally` bloğunun **çalışmasıdır**: `close` çağrısı askıdaki gövdeyi durduğu noktadan
uyandırır, orada bir istisna doğurur ve `finally` bloklarını yürütür. İz satırı bunu
kanıtlıyor, üstelik o anki üretim sayısını da yazıyor.

Bunun pratikteki karşılığı şudur: bir üreteç açık bir kaynak üzerinde çalışıyorsa, akışın
yarıda bırakılması o kaynağı asılı bırakmaz. Python Temelleri kursunun bağlam yöneticileri
dersi serbest bırakmanın istisna durumunda da yapıldığını kurmuştu; üreteç gövdesindeki
`try`/`finally` aynı güvenceyi **askıya alınmış** bir çerçeve için verir. Tembel olan işi
erteler, sorumluluğu ertelemez.

## Özet

- `yield` içeren bir işlev çağrıldığında gövdesinden tek satır çalışmaz; geriye bir üreteç
  nesnesi döner. `return` çerçeveyi yıkar, `yield` askıya alır.
- Bin öğelik akışta kavrama kurulumda **1000** nesne var eder, üreteç ifadesi ve üreteç
  işlevi çağrısı **0**; üç öğe istendiğinde ikisi **3**'te kalır. Yazımlar tek deyimlik ve
  benzerdir, sayılar değildir.
- Üreteç önceki dersin sözleşmesini imzalar: `iter(g) is g` doğrudur, akış tek geçişliktir
  ve ikinci geçiş **0** öğe verir. Elle yazılan yineleyici sınıfının yaptığı işi dil yapar.
- Gövde her `yield`'de durur ve bir sonraki istekle o noktadan devam eder; yerel adlar
  arada korunur. Sona ulaşıldığında `return` değeri `StopIteration` üzerinde taşınır ve
  `for` ile gezen taraf onu görmez.
- `yield from` ara kap kurmadan yetki devreder: ilk öğeye dek **1** üretim. Aynı işi iki
  listeyi ekleyerek yapmak ilk öğeden önce **1000** üretim ve üç kap gerektirir.
- `yield` bir ifadedir ve `send` ile gönderilen değeri döndürür; bin öğelik akış üç öğeden
  sonra `close` ile bırakıldığında üretim **3**'te kalır ama gövdedeki `finally` bloğu yine
  çalışır.

## Sonraki Adım

Bu ders yalnız kurulum anını ölçtü ve orada uçurum vardı: **1000**'e karşı **0**. Ama akış
er ya da geç tüketilir — bin öğe gerçekten toplanacaksa üreteç de o bin nesneyi üretmek
zorunda. Sonraki ders tam bu soruyu sorar: aynı işi sonuna kadar götüren iki yazım, işin
sonunda kaç nesne üretmiş olur ve kaçını hâlâ elinde tutar? Yanıtın ilk yarısı beklenen,
ikinci yarısı beklenmedik çıkacak — ve tembelliğin gerçekte neyi azalttığı ancak orada
görünecek.
