---
title: 'Yerleşik Fonksiyonlar'
source: 'https://academia.sh/tr/kurslar/python-temelleri/yerlesik-fonksiyonlar'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:28+00:00'
license: 'CC BY-SA 4.0'
---

# Yerleşik Fonksiyonlar

Yerleşikler iş yapan işlevler değil, protokol çağıran ince kabuklardır: sekiz yerleşik yirmi bir çağrı üretir, toplayanların hepsi aynı beşli diziyi kurar ve protokolü tanımlamayan bir nesnede üçü değer verirken beşi TypeError fırlatır.

Önceki ders ad aramasının dört düzeyini ölçtü ve son basamaktaki adları yalnız
gölgelenecek bir şey olarak gösterdi. O düzeyde duran adlar dilin en çok kullanılanlarıdır
ve şimdiye kadar ölçülen her protokole doğrudan bağlanırlar.

Bu dersin sorusu, o adların ne yaptığı değil — **kendilerinin bir iş yapıp yapmadığıdır**.
`len` uzunluğu kendisi mi hesaplıyor, yoksa nesneye mi soruyor? `sorted` sıralamayı kendisi
mi biliyor, yoksa karşılaştırmayı nesneye mi bırakıyor? Kursun ölçü ekseni bu soruya bir
yanıt öneriyor: sözdizim bir kısaltmaysa, yerleşikler de birer kısaltma olabilir. Ölçüm
bunu sınar.

## Yerleşik Bir Kabuktur

Buraya kadarki dört ders sözdizim biçimlerini ölçtü: `if`, `for`, `while`, çağrı yazımı.
Yerleşikler sözdizim değildir; sıradan işlevlerdir ve çıplak bir adla çağrılırlar. Ama
ölçü ekseni ikisi için de aynıdır — bir yerleşiğin sayısı da, hangi özel yöntemi kaç kez
çağırdığıdır.

Sözleşme şudur: yerleşik, işi kendisi yapmaz. Nesnede adı belli bir özel yöntemi arar,
bulursa çağırır ve döndürdüğünü verir. `len` uzunluğu saymaz, `__len__`'e sorar; `str`
metni kurmaz, `__str__`'e sorar; `iter` bir yineleyici üretmez, `__iter__`'den ister.
Yerleşiğin katkısı iş değil, **tek bir çağrı adı**: nesnenin tipi ne olursa olsun aynı ad
kullanılır.

Bunun sonucu, yerleşiklerin tipe göre değil **protokole göre** çalışmasıdır. Bir nesnenin
`len` ile ölçülüp ölçülemeyeceğini belirleyen şey sınıfının adı değil, `__len__`
tanımlayıp tanımlamadığıdır.

Bu tasarımın pratik karşılığı, yeni bir sınıfın yerleşiklerle çalışmak için hiçbir şey
**devralmak** ya da hiçbir yere **kaydolmak** zorunda olmamasıdır. Sınıf yalnız beklenen
adı taşıyan bir yöntem tanımlar; yerleşik onu bulur. Ortak tanımın dördüncü okuması burada
ikinci kez ödenir — bir nesnenin ne yapabildiğini tipinin adı değil, tanımladığı özel
yöntemler belirler. Yerleşiğin nesne hakkında bildiği tek şey, aradığı yöntemin orada olup
olmadığıdır.

## Toplayan Yerleşikler

İkinci bir öbek, tek bir yöntem çağırmakla yetinmez. `list`, `sum` ve `sorted` nesnenin
**bütün öğelerini** ister; bunun için yineleme protokolünü baştan sona yürütürler.
Beklenen dizi ikinci dersin ölçtüğü diziyle aynı olmalıdır: bir `__iter__`, ardından öğe
sayısından bir fazla `__next__`.

Bu öbeğin bir sonucu, öğeleri **toplamanın** her zaman öğe sayısı kadar iş olmasıdır:
yerleşik kaç öğe olduğunu baştan bilmez ve bilemez, çünkü yineleme protokolü bir sayı
bildirmez. Toplama ancak `StopIteration` geldiğinde biter — yani öğeler tükenene kadar
sürer.

`sorted` bu öbek içinde ayrı durur, çünkü topladıktan sonra bir de **sıralaması** gerekir.
Toplamak bir protokol, sıralamak başka bir protokoldür; ikincisi öğeler arasında
karşılaştırma yapar. Bir yerleşiğin tek bir özel yöntemle eşleştiği varsayımı burada
sınanır.

## Protokol Yoksa

Üçüncü ölçü, yöntemin **bulunamadığı** durumdur. Ortak tanımın dördüncü okuması bunu
söylüyordu: protokol yoksa sözdizim de yoktur. Yerleşikler için de geçerli mi?

Yanıtın tek olmadığı baştan bellidir, çünkü birinci derste ölçülen bir durum var: doğruluk
sınaması, hiçbir yöntem bulamadığında hata vermiyor, nesneyi **doğru** sayıyordu. Demek ki
en az bir yerleşiğin varsayılan davranışı var. Kaçının var, kaçının yok — ölçüm bunu
ayırır.

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

- **PA31** — Kâhin kurgunun kendisidir: her özel yöntem çağrıldığında adını kaydeder ve
  yerleşiğin hangi yöntemi çağırdığı bu kayıttan okunur.
- **PA32** — İki sınıf kullanılır. `Akis` yalnız yineleme ve karşılaştırma yöntemlerini
  tanımlar; `Izci` ona uzunluk ve metin yöntemlerini ekler. Toplayan yerleşikler
  **`Akis`** üzerinde ölçülür — böylece ölçülen dizi yalnız yineleme protokolünden gelir.
- **PA33** — `Sessiz` hiçbir özel yöntem tanımlamaz ve "protokol yok" durumunun ölçüsüdür.
- **PA34** — Sonuçlar **değer olarak basılmaz**, yalnız "değer üretti" ya da istisnanın
  sınıfı yazılır. Yöntem tanımlamayan bir nesnenin metin karşılığı ortama bağlı bilgi
  taşır; ölçüme girmez.
- **PA35** — `Izci.__repr__` gövdesinde `__str__`'i çağırır; bu, ortak tanımdaki
  davranıştır ve iki çağrının nedeni budur.
- **PA36** — Sıralama ölçümünde **çağrı sayısı değil, çağrılan protokollerin kümesi**
  yazılır. Karşılaştırma sayısı sıralama düzeninin bir ayrıntısıdır ve ölçünün parçası
  değildir.
- **PA37** — Toplam çağrı sayısı yalnız bu sekiz yerleşiğe ve üç öğelik nesneye özgüdür.
- **PA38** — Anahtar işlevi ölçümünde `key` olarak `len` yerleşiği verilir; böylece
  anahtarın çağrıldığı her yer kayda düşer ve öğe başına kaç kez çağrıldığı sayılabilir.

## Ölçüm

```python
"""Yerlesiklerin sozlesmesi: her biri hangi ozel yontemi cagirir."""

KAYIT = []


def kaydet(ad):
    KAYIT.append(ad)


class Akis:
    """Yalniz yineleme ve siralama protokolu; __len__ tanimlamaz."""

    def __init__(self, ogeler=(1, 2, 3)):
        self.ogeler = list(ogeler)

    def __iter__(self):
        kaydet("__iter__")
        self._i = 0
        return self

    def __next__(self):
        kaydet("__next__")
        if self._i >= len(self.ogeler):
            raise StopIteration
        deger = self.ogeler[self._i]
        self._i += 1
        return deger

    def __lt__(self, o):
        kaydet("__lt__")
        return len(self.ogeler) < len(o.ogeler)


class Izci(Akis):
    """Uzunluk ve metin protokollerini de tanimlar."""

    def __len__(self):
        kaydet("__len__")
        return len(self.ogeler)

    def __str__(self):
        kaydet("__str__")
        return f"Izci{tuple(self.ogeler)}"

    def __repr__(self):
        kaydet("__repr__")
        return self.__str__()


class Bosluksuz(Izci):
    """__bool__ tanimli: dogruluk sinamasi __len__'e dusmez."""

    def __bool__(self):
        kaydet("__bool__")
        return len(self.ogeler) > 0


class Sessiz:
    """Hicbir ozel yontem tanimlamaz."""


def olc(islev):
    KAYIT.clear()
    try:
        islev()
        durum = "değer üretti"
    except Exception as e:
        durum = f"!{type(e).__name__}"
    return list(KAYIT), durum


TEKIL = (("len(n)", len, Izci), ("str(n)", str, Izci), ("repr(n)", repr, Izci),
         ("bool(n)", bool, Izci), ("iter(n)", iter, Izci))
TOPLAYAN = (("list(n)", list, Akis), ("sum(n)", sum, Akis),
            ("sorted(n)", sorted, Akis))

print(f"{'yerleşik':<12s} {'çağrı':>6s}  çağrılan protokol dizisi")
toplam = 0
for ad, f, sinif in TEKIL + TOPLAYAN:
    c, _ = olc(lambda f=f, s=sinif: f(s()))
    toplam += len(c)
    print(f"  {ad:<10s} {len(c):6d}  {' '.join(c)}")
print(f"\nsekiz yerleşik, toplam {toplam} çağrı")

print()
print(f"{'yerleşik':<12s} {'protokolü tanımlayan nesne':<27s} tanımlamayan nesne")
for ad, f, sinif in TEKIL + TOPLAYAN:
    _, d1 = olc(lambda f=f, s=sinif: f(s()))
    _, d2 = olc(lambda f=f: f(Sessiz()))
    print(f"  {ad:<10s} {d1:<27s} {d2}")

print()
c, _ = olc(lambda: bool(Izci()))
print(f"bool(__bool__ tanımsız) -> {' '.join(c)}")
c, _ = olc(lambda: bool(Bosluksuz()))
print(f"bool(__bool__ tanımlı)  -> {' '.join(c)}")

print()
c, _ = olc(lambda: sorted(Akis()))
print(f"sorted(tek nesne, öğeleri sayı)  -> {' '.join(sorted(set(c)))}")
UCLU = [Akis((1, 2, 3)), Akis((1,)), Akis((1, 2))]
c, _ = olc(lambda: sorted(UCLU))
print(f"sorted(üç nesnelik liste)        -> {' '.join(sorted(set(c)))}")

print()
UCLU_IZCI = [Izci((1, 2, 3)), Izci((1,)), Izci((1, 2))]
print(f"{'üç nesnelik liste':<28s} {'çağrılan protokol':<20s} karşılaştırma nesneye sorulur mu")
for ad, f in (("sorted(liste)", lambda: sorted(UCLU_IZCI)),
              ("sorted(liste, key=len)", lambda: sorted(UCLU_IZCI, key=len))):
    c, _ = olc(f)
    print(f"  {ad:<26s} {' '.join(sorted(set(c))):<20s}"
          f" {'evet' if '__lt__' in c else 'hayır'}")
c, _ = olc(lambda: sorted(UCLU_IZCI, key=len))
print(f"  key=len çağrısı öğe başına: {c.count('__len__')} / {len(UCLU_IZCI)} öğe")
```

```
yerleşik      çağrı  çağrılan protokol dizisi
  len(n)          1  __len__
  str(n)          1  __str__
  repr(n)         2  __repr__ __str__
  bool(n)         1  __len__
  iter(n)         1  __iter__
  list(n)         5  __iter__ __next__ __next__ __next__ __next__
  sum(n)          5  __iter__ __next__ __next__ __next__ __next__
  sorted(n)       5  __iter__ __next__ __next__ __next__ __next__

sekiz yerleşik, toplam 21 çağrı

yerleşik     protokolü tanımlayan nesne  tanımlamayan nesne
  len(n)     değer üretti                !TypeError
  str(n)     değer üretti                değer üretti
  repr(n)    değer üretti                değer üretti
  bool(n)    değer üretti                değer üretti
  iter(n)    değer üretti                !TypeError
  list(n)    değer üretti                !TypeError
  sum(n)     değer üretti                !TypeError
  sorted(n)  değer üretti                !TypeError

bool(__bool__ tanımsız) -> __len__
bool(__bool__ tanımlı)  -> __bool__

sorted(tek nesne, öğeleri sayı)  -> __iter__ __next__
sorted(üç nesnelik liste)        -> __lt__

üç nesnelik liste            çağrılan protokol    karşılaştırma nesneye sorulur mu
  sorted(liste)              __lt__               evet
  sorted(liste, key=len)     __len__              hayır
  key=len çağrısı öğe başına: 3 / 3 öğe
```

## Bire Bir Eşleşme

Üst tablonun ilk beş satırı sözleşmeyi doğruluyor. `len` **bir** çağrı yapıyor ve çağırdığı
şey `__len__`; `str` bir çağrı, `__str__`; `iter` bir çağrı, `__iter__`. Yerleşiğin
gövdesinde uzunluk sayan, metin kuran ya da yineleyici üreten bir kod yok — olsaydı çağrı
sayısı sıfır olurdu, çünkü nesneye hiç sormaya gerek kalmazdı.

`repr` satırındaki **2** bir istisna gibi görünüyor ama değil. `repr` yine tek bir yöntem
çağırıyor: `__repr__`. İkinci çağrı yerleşikten gelmiyor — `__repr__` gövdesinin kendisi
`__str__`'i çağırıyor. Yerleşiğin sözleşmesi bozulmuş değil; ölçülen dizi, çağrılan
yöntemin **kendi** yaptığı işi de gösteriyor.

`bool` satırı birinci dersin sonucunu tekrar üretiyor: nesnede `__bool__` tanımlı olmadığı
için sınama `__len__`'e düşüyor. Alt bölümdeki iki satır ikisini yan yana koyuyor —
`__bool__` tanımlıyken **yalnız o** çağrılıyor, `__len__` sınamaya hiç girmiyor. Bir
yerleşiğin tek bir yöntemle eşleştiği kuralının tek gerçek istisnası budur: `bool` bir
değil, **sıralı iki** yöntem arar.

## Toplayanların Ortak Dizisi

Son üç satır aynı diziyi veriyor: bir `__iter__`, dört `__next__`, toplam **5**. Üç ayrı
yerleşik — biri liste kuruyor, biri toplam alıyor, biri sıralıyor — ve üçü de öğeleri tam
olarak aynı biçimde topluyor.

Dizi ikinci dersin ölçtüğü diziyle birebir aynıdır ve aynı nedenle **bir fazladır**: üç
öğe için dört `__next__`, sonuncusu `StopIteration` fırlatarak toplamanın bittiğini
bildiriyor. `for` döngüsü, `list`, `sum` ve `sorted` — dördü de aynı protokolü aynı sayıda
çağırıyor. Aralarındaki fark topladıkları öğelerle **ne yaptıklarıdır**, nasıl
topladıkları değil.

Bunun pratik sonucu, yineleme protokolünü tanımlayan bir nesnenin bu yerleşiklerin
tamamıyla kendiliğinden çalışmasıdır. Sınıfa `list` desteği, `sum` desteği, `sorted`
desteği ayrı ayrı eklenmez; `__iter__` ile `__next__` yazıldığı anda üçü de gelir.

## Sıralamanın İki Protokolü

Alt iki satır `sorted` yerleşiğini ayırıyor ve tek yöntemle eşleşmediğini gösteriyor.

Birinci satırda sıralanan nesnenin **öğeleri sayı**. Çağrılan protokoller `__iter__` ve
`__next__` — yani yalnız toplama. Karşılaştırma da yapılıyor elbette, ama sayılar arasında;
kurgunun nesnesi o karşılaştırmaya girmiyor ve kayda hiçbir şey düşmüyor.

İkinci satırda sıralanan şey **üç nesnelik bir liste**. Bu kez kayıtta yalnız `__lt__` var.
Liste zaten bir liste olduğu için toplama aşamasında kurgunun protokolü çağrılmıyor;
sıralama aşamasında ise her karşılaştırma nesneye soruluyor.

İki satır birlikte okunduğunda `sorted` iki ayrı protokol çağırıyor: öğeleri **toplamak**
için yineleme protokolü, **sıralamak** için karşılaştırma protokolü. Hangisinin kayda
düştüğü, kurgunun nesnesinin hangi rolde bulunduğuna bağlı — dışta kapsayıcı olarak mı,
içte öğe olarak mı.

Buradan çıkan okuma şudur: `sorted` sıralamayı bilmez, **karşılaştırmayı** nesneye sorar.
Sıralama düzenini belirleyen şey yerleşiğin gövdesi değil, öğelerin `__lt__` gövdesidir.
Yerleşik yalnız hangi öğenin hangisinden önce geleceğini sorar ve gelen yanıta uyar.
Aynı liste, öğelerin `__lt__` tanımı değiştirilerek başka bir sırayla dizilir ve `sorted`
çağrısında tek bir karakter değişmez.

## Anahtar Protokolü Değiştirir

Son tablo aynı çağrının bir anahtarlı argümanla nasıl **başka bir protokole** geçtiğini
ölçüyor. İki satırın sıraladığı liste aynı, sıralanan nesneler aynı; değişen tek şey
`key` argümanının verilip verilmediği.

Anahtarsız çağrıda kayda düşen protokol `__lt__` — karşılaştırma nesnelere soruluyor.
Anahtarlı çağrıda kayda düşen protokol `__len__` ve `__lt__` **hiç çağrılmıyor**. Sağdaki
sütun bunu doğrudan söylüyor: karşılaştırma artık nesneye sorulmuyor.

Olan şey şudur: `key` verildiğinde `sorted` önce her öğeye anahtar işlevini uygular, sonra
sıralamayı **dönen anahtar değerleri** üzerinde yapar. Nesneler kendi aralarında hiç
karşılaştırılmaz; karşılaştırılan şey onların anahtarlarıdır. Bu yüzden `__lt__`
tanımlamayan nesneler bile uygun bir anahtarla sıralanabilir — sıralanabilirlik nesnenin
değil, **anahtarın** özelliği hâline gelir.

Son satır anahtarın kaç kez çağrıldığını veriyor: üç öğe için **3** çağrı, yani öğe başına
tam bir kez. Anahtar her karşılaştırmada yeniden hesaplanmıyor; bir kez hesaplanıp
saklanıyor. Bunun sonucu, pahalı bir anahtar işlevinin sıralama boyunca bir kez ödenmesidir
— karşılaştırma sayısı ne olursa olsun.

## Varsayılanı Olan ve Olmayan

Orta tablo protokolün bulunamadığı durumu ölçüyor ve sekiz yerleşik **ikiye ayrılıyor**.

Beşi hiçbir varsayılan tanımıyor: `len`, `iter`, `list`, `sum` ve `sorted`, yöntemi
bulamadığında bir değer değil `TypeError` üretiyor. Bu yerleşikler için ortak tanımın
dördüncü okuması harfiyen geçerli — protokol yoksa yerleşik de yoktur.

Üçü değer üretiyor. `str` ile `repr`, yöntem tanımlanmamış bir nesne için de bir metin
veriyor; dil her nesne için varsayılan bir metin karşılığı tanımlar. `bool` ise birinci
dersin üçüncü basamağını uyguluyor ve nesneyi doğru sayıyor.

Ayrımın gerekçesi sorunun yanıtlanabilir olup olmamasıdır. "Bu nesnenin uzunluğu kaçtır?"
sorusunun nesne söylemezse makul bir yanıtı yoktur; uydurulan her sayı yanlış olurdu.
"Bu nesnenin metin karşılığı nedir?" sorusunun ise her nesne için üretilebilecek bir
yanıtı vardır. Yerleşiğin varsayılanı olması, sorunun **nesneden bağımsız** bir yanıtının
bulunmasına bağlıdır.

Bu ayrımın bir bedeli var ve tabloda görünmüyor: varsayılanı olan yerleşikler **sessizce**
çalışır. `__len__` yazmayı unutan bir sınıf `len` çağrısında hemen belli olur; `__bool__`
yazmayı unutan sınıf ise hiçbir belirti vermeden her `if` sınamasından doğru döner.
Hatanın erken çıkması, `TypeError` üreten yerleşiklerin sağladığı bir güvencedir.

## Özet

- Yerleşikler iş yapan işlevler değil, nesnedeki özel yöntemi çağıran **ince kabuklardır**;
  `len` uzunluğu saymaz, `str` metni kurmaz, `iter` yineleyici üretmez — üçü de sorar.
- Sekiz yerleşik üç öğelik nesnede toplam **21** çağrı üretir; ilk beşi birer çağrıyla
  tek bir yöntemle eşleşir, `bool` ise sıralı iki yöntem arar ve `__bool__` yoksa
  `__len__`'e düşer.
- `list`, `sum` ve `sorted` aynı beşli diziyi kurar — bir `__iter__`, dört `__next__` — ve
  bu, `for` döngüsünün dizisiyle birebir aynıdır; yineleme protokolünü yazan bir sınıf
  üçünü birden kazanır.
- `sorted` tek değil **iki** protokol çağırır: toplamak için yineleme, sıralamak için
  karşılaştırma. Sıralama düzenini yerleşiğin gövdesi değil, öğelerin `__lt__` gövdesi
  belirler.
- Anahtarlı argüman verildiğinde `sorted` karşılaştırmayı nesneye hiç sormaz: `__lt__`
  yerine anahtar işlevi çağrılır — öğe başına **tam bir kez** — ve sıralanabilirlik
  nesnenin değil anahtarın özelliği olur.
- Protokolü tanımlamayan bir nesnede sekiz yerleşiğin **beşi** `TypeError` verir, **üçü**
  değer üretir; varsayılanı olanlar nesneden bağımsız bir yanıtı bulunanlardır ve
  eksikliği sessizce geçiştirme bedelini taşırlar.

## Sonraki Adım

Buraya kadar ölçülen her protokol **beklenen** yolu izledi. Sözdizim bir yöntem aradı,
buldu ve çağırdı; bulamadığında ikinci bir yönteme düştü; o da yoksa ya bir varsayılan
uyguladı ya da düzenli bir biçimde `TypeError` fırlattı. Döngüyü bitiren `StopIteration`
bile bir kaza değil, protokolün planlanmış son adımıydı.

Peki bir protokol **başarısız olursa**? Çağrılan yöntem bulunuyor, çalışıyor, ama işini
tamamlayamıyor — dosya yok, sayı çevrilemiyor, dizin sınırın dışında. Bu derste
`TypeError` bir kez göründü, önceki derslerde `NameError`, `UnboundLocalError`, `IndexError`
ve `StopIteration` göründü. Beşi de birer sınıftı ve hepsi aynı yazımla yakalanabilir.
Sonraki ders bu sınıfların birbiriyle ilişkisini kurar: hangisini yakalamak hangilerini de
yakalar, ve geniş bir yakalama neyi yutar.
