---
title: 'Kalıtım ve Yöntem Çözümleme Sırası'
source: 'https://academia.sh/tr/kurslar/python-nesne-ve-tipler/kalitim-ve-yontem-cozumleme-sirasi'
course: 'Nesneye Dayalı Python ve Tipler'
language: tr
updated: '2026-08-17T18:10:30+00:00'
license: 'CC BY-SA 4.0'
---

# Kalıtım ve Yöntem Çözümleme Sırası

Dört yeteneğin gövdesi kalıtımda üç ayrı sınıfa dağılır ve `Belge` bunların 0'ını kendi gövdesinde yazar, bileşimde `Sarmal` 4'ünü de yazar; gövdesi `Kayit`'te yazılı olan `bicimle` yöntemi `<Imzali>` basar.

Önceki ders tek sınıflı bir ağaçta yanıtın hep aynı yerden geldiğini gösterdi: arama örneğin
sözlüğüne bakıyor, bulamazsa sınıfa gidiyor ve orada bitiyordu. Son ölçüm sınırı çoktan
çizmişti — gövdesi `Bicimci`'de yazılı bir sınıf yöntemi `AltBicimci` üzerinden çağrıldığında
`cls`'e bağlanan sınıf `AltBicimci` oldu. Gövdenin durduğu yer ile çağrının yanıtlandığı yer
ayrıldı.

Bu ders o ayrımı büyütür ve kursun **ikinci iddiasını** öder. Aynı dört yetenek iki ayrı
tasarımla verilecek: biri kalıtım ağacı, öteki bileşim. İki tasarım da aynı sonuçları
üretecek. Sorulan şey sonuç değil: **her yeteneğin gövdesi hangi sınıfta yazılı?** Soru ölçüye
elverişlidir, çünkü yanıtı görüşe değil koda bakılarak verilir — bir sınıfın sözlüğünde bir ad
ya vardır ya yoktur.

## Aynı Dört Yetenek, İki Tasarım

Kalıtım tarafı dört sınıftan oluşur. `Kayit` iki yetenek taşır: `kaynak` ve onu çağıran
`bicimle`. `Zamanli` ondan türer ve `damga` ekler. `Imzali` da ondan türer, `imza` ekler ve
`kaynak`'ı **yeniden yazar**. `Belge` ikisinden birden türer ve gövdesi boştur.

Bileşim tarafı tek sınıftır. `Sarmal` hiçbir şeyden türemez; iki nesneyi kendi içinde tutar
ve dört yeteneğin dördünü de kendi gövdesinde yazıp çağrıyı içerideki nesneye iletir.

Bir yeteneğin gövdesinin nerede yazılı olduğunu **yöntem çözümleme sırası (method resolution
order)** söyler. Her sınıfın böyle bir sırası vardır: aramanın hangi sınıfları hangi düzende
gezeceğini veren, tanım anında bir kez hesaplanmış bir liste. `saglayan` işlevi bu listeyi
gezer ve adı ilk taşıyan sınıfı döndürür.

`Belge`'nin gövdesinin boş olması bir eksiklik değil, ölçümün kendisidir. O gövde tek bir şey
bildirir: hangi sınıflardan, **hangi sırayla** türendiği. Sınıfın bütün davranışı bu tek
bildirimden doğar ve bildirim değiştiğinde davranış da değişir — tabanların yeri değiştirilse
`kaynak`'ı yanıtlayan sınıf değişir, `Belge`'nin gövdesine tek satır eklense yanıt oraya
kayar. Bileşimde bu bildirim yoktur; `Sarmal`'ın davranışı yalnız kendi gövdesinden okunur.

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

- **SN16** — Dört sınıflı ağaç ve `Sarmal` ortak kurgunun tanımladığı biçimdedir; yeteneklerin
  yerleşimi değiştirilmemiştir.
- **SN17** — Ölçülen dört yetenek `kaynak`, `bicimle`, `damga` ve `imza`'dır; ölçüm çağrının
  **sonucuna** değil, gövdenin **yazıldığı sınıfa** bakar.
- **SN18** — Bileşim sütunu sabit değildir, `Sarmal`'ın kendi sözlüğünden okunmuş olsaydı da
  aynı çıkardı: dört adın dördü de o gövdede yazılıdır.
- **SN19** — Çözümleme sırası basılırken listenin son öğesi (bütün sınıfların ortak tabanı)
  kırpılır; ölçülen şey kurgunun kendi dört sınıfıdır.

```python
"""Cagriyi kim yanitladi: kalitim ile bilesim yan yana."""


class Kayit:
    def kaynak(self):
        return "Kayit"

    def bicimle(self):
        return f"<{self.kaynak()}>"


class Zamanli(Kayit):
    def damga(self):
        return "zaman"


class Imzali(Kayit):
    def kaynak(self):
        return "Imzali"

    def imza(self):
        return "imza"


class Belge(Zamanli, Imzali):
    pass


class Sarmal:
    """Ayni yetenegi bilesimle veren nesne: yanit veren acikca yazilir."""

    def __init__(self):
        self.zamanli = Zamanli()
        self.imzali = Imzali()

    def kaynak(self):
        return self.imzali.kaynak()

    def damga(self):
        return self.zamanli.damga()

    def imza(self):
        return self.imzali.imza()

    def bicimle(self):
        return f"<{self.kaynak()}>"


def saglayan(sinif, ad):
    """Bir ozniteligi hangi sinif sagliyor: cozumleme sirasinda ilk bulan."""
    for s in sinif.__mro__:
        if ad in s.__dict__:
            return s.__name__
    return None


YETENEKLER = ("kaynak", "bicimle", "damga", "imza")

k = {ad: saglayan(Belge, ad) for ad in YETENEKLER}
b = {ad: "Sarmal" for ad in YETENEKLER}

print(f"{'yetenek':<10s} {'kalıtımda yanıtlayan':>21s} {'bileşimde yanıtlayan':>21s}")
for ad in YETENEKLER:
    print(f"{ad:<10s} {k[ad]:>21s} {b[ad]:>21s}")
print()
print("çözümleme sırası: " + " -> ".join(s.__name__ for s in Belge.__mro__[:-1]))
print(f"Belge().bicimle() -> {Belge().bicimle()} | Sarmal().bicimle() -> "
      f"{Sarmal().bicimle()}")
print(f"kalıtımda gövdesi Belge'de yazılı yetenek: "
      f"{sum(1 for a in YETENEKLER if k[a] == 'Belge')}/{len(YETENEKLER)}; "
      f"bileşimde: {sum(1 for a in YETENEKLER if b[a] == 'Sarmal')}/{len(YETENEKLER)}")
```

```
yetenek     kalıtımda yanıtlayan  bileşimde yanıtlayan
kaynak                    Imzali                Sarmal
bicimle                    Kayit                Sarmal
damga                    Zamanli                Sarmal
imza                      Imzali                Sarmal

çözümleme sırası: Belge -> Zamanli -> Imzali -> Kayit
Belge().bicimle() -> <Imzali> | Sarmal().bicimle() -> <Imzali>
kalıtımda gövdesi Belge'de yazılı yetenek: 0/4; bileşimde: 4/4
```

Son satır iddianın kendisidir. `Belge` dört yeteneğin **0**'ını kendi gövdesinde taşır;
`Sarmal` **4**'ünü de taşır. `Belge`'nin gövdesi okunduğunda görülen tek şey iki taban adıdır;
nesnenin ne yapabildiği o gövdede **yazılı değildir**. `Sarmal`'ın gövdesi okunduğunda ise
dört yetenek de, her birinin çağrıyı kime ilettiği de görünür.

Sol sütun yanıtın üç ayrı sınıfa dağıldığını gösteriyor: `kaynak` `Imzali`'den, `bicimle`
`Kayit`'ten, `damga` `Zamanli`'den geliyor. `kaynak` iki sınıfta birden yazılıdır — hem
`Kayit`, hem `Imzali` — ama çözümleme sırasında `Imzali` önce geldiği için yanıtı o veriyor.
`Kayit`'teki gövde hâlâ oradadır ve hiç çağrılmaz.

Asıl ince nokta ikinci satırdadır. `bicimle` gövdesi **`Kayit`'te** yazılıdır ve o gövdede
`self.kaynak()` yazar. Gövde `Kayit`'in içinde durduğu için oradaki `kaynak`'ı çağıracağı
düşünülebilir; **çağırmıyor.** Çağrı `self` üzerinden yapılır ve `self` bir `Belge`
örneğidir — arama `Belge`'nin sırasında yapılır ve `Imzali`'de durur. Sonuç `<Imzali>` çıkar.
**Bir gövdeyi okumak, o gövdenin ne üreteceğini söylemez;** onu, çağrı anındaki nesnenin
çözümleme sırası söyler. `Sarmal` aynı sonucu verir, ama orada iletimin nereye gittiği
gövdenin içinde yazılıdır.

Programlama Paradigmaları kursu bileşimin kalıtıma tercih edilmesini bir **tasarım ilkesi**
olarak, kırılgan üst sınıf sorunuyla birlikte kurmuştu; **bu tartışma tekrarlanmaz.** Burada
ölçülen şey ilkenin gerekçesi değil, ölçülebilir karşılığıdır: gövdenin **nerede yazılı**
olduğu. 0/4 ile 4/4 aynı davranışın iki ayrı okunabilirlik bedelidir.

İki sayının yönü terstir ve seçim tam olarak burada yapılır. Kalıtımda beşinci bir yetenek
eklemenin bedeli **0** satırdır: `Zamanli`'ye yazılan bir yöntem `Belge`'de kendiliğinden
görünür. Bileşimde bedel **1** satırdır — `Sarmal`'a bir iletim yazmak gerekir. Buna karşılık
"bu çağrıyı kim yanıtlıyor" sorusunun bedeli kalıtımda dört sınıf gövdesini ve aralarındaki
sırayı okumak, bileşimde tek gövdeyi okumaktır. Kalıtım yazımı kısaltır ve okumayı uzatır;
bileşim yazımı uzatır ve okumayı kısaltır.

Ayrımın bir de nesne tarafı vardır ve iki tanımdan doğrudan okunur. Bir `Belge` örneği **tek**
nesnedir; dört sınıfın gövdeleri tek bir sözlük üzerinde çalışır ve `Kayit`'in tutacağı her
durum o tek sözlükte, **bir kez** bulunur. Bir `Sarmal` örneği ise **üç** nesnedir — kendisi ve
`__init__` içinde var ettiği iki nesne — ve `Kayit`'ten gelen durum ikisinde **ayrı ayrı**
tutulur. İki tasarım aynı çağrılara aynı yanıtı verir ama durumu farklı sayıda yerde saklar:
kalıtımda paylaşım kaçınılmazdır, bileşimde paylaşım ancak açıkça yazılırsa olur.

## Sıra Nasıl Kuruluyor

`Belge -> Zamanli -> Imzali -> Kayit` sırası keyfî değildir ve iki kuralla üretilir: her sınıf
kendi tabanlarından **önce** gelir, ve tabanlar sınıf gövdesinde **yazıldıkları sırayla**
korunur. `Kayit` en sonda durur, çünkü hem `Zamanli`'nin hem `Imzali`'nin tabanıdır ve ikisi
de ondan önce gelmek zorundadır.

Bu iki kural her taban sıralaması için sağlanamaz. Sağlanamadığında sınıf **kurulamaz** ve
hata örnek var edilirken değil, `class` deyimi çalışırken alınır.

- **SN20** — Dört taban sıralaması aynı üç sınıftan kurulur; kurulan sınıfın kendisi çıktıdan
  düşürülür, yalnız ondan sonraki sıra basılır.
- **SN21** — Kurulamayan sıralamada ünlem önekiyle **istisnanın adı** kaydedilir.
- **SN22** — Sınıflar önceki bloğun tanımlarıdır; ağaç değiştirilmemiştir.

```python
def kurmayi_dene(tabanlar):
    """Verilen taban sirasiyla bir sinif kurulabiliyor mu?"""
    try:
        s = type("Deneme", tabanlar, {})
    except TypeError as e:
        return f"!{type(e).__name__}"
    return " -> ".join(t.__name__ for t in s.__mro__[1:-1])


print(f"{'taban sırası':<22s} {'kurulan sınıftan sonraki sıra':<34s}")
for tabanlar in ((Zamanli, Imzali), (Imzali, Zamanli),
                 (Zamanli, Kayit), (Kayit, Zamanli)):
    ad = "(" + ", ".join(t.__name__ for t in tabanlar) + ")"
    print(f"{ad:<22s} {kurmayi_dene(tabanlar):<34s}")

print()
print(f"Kayit'in Belge sırasındaki yeri: "
      f"{Belge.__mro__.index(Kayit)} (dört sınıfın sonuncusu)")
print(f"Zamanli'nin doğrudan tabanı: "
      f"{', '.join(t.__name__ for t in Zamanli.__bases__)}")
print(f"Belge sırasında Zamanli'den hemen sonra gelen: "
      f"{Belge.__mro__[Belge.__mro__.index(Zamanli) + 1].__name__}")
```

```
taban sırası           kurulan sınıftan sonraki sıra     
(Zamanli, Imzali)      Zamanli -> Imzali -> Kayit        
(Imzali, Zamanli)      Imzali -> Zamanli -> Kayit        
(Zamanli, Kayit)       Zamanli -> Kayit                  
(Kayit, Zamanli)       !TypeError                        

Kayit'in Belge sırasındaki yeri: 3 (dört sınıfın sonuncusu)
Zamanli'nin doğrudan tabanı: Kayit
Belge sırasında Zamanli'den hemen sonra gelen: Imzali
```

Dört sıralamanın **üçü** kuruluyor, **biri** düşüyor. İlk iki satır taban yazım sırasının
sonucu doğrudan belirlediğini gösteriyor: yerler değişince `kaynak`'ı yanıtlayan sınıf da
değişir. Dördüncü satır sınırı çiziyor — `Kayit` önce, türevi `Zamanli` sonra yazıldığında
"her sınıf tabanlarından önce gelir" kuralı sağlanamaz ve sınıf hiç kurulamaz. Bu bir çalışma
zamanı hatası değildir; **tanım anında** alınır. Sıra her sınıf için bir kez hesaplanır ve
sınıfın üzerinde saklanır; her öznitelik erişiminde yeniden kurulmaz. Aramanın bedeli bu
yüzden ağacın biçimine değil, adın sırada kaçıncı sınıfta bulunduğuna bağlıdır.

Son üç satır ilk tablodaki sıranın nereden geldiğini kapatıyor. `Kayit`, `Zamanli`'nin
**doğrudan** tabanıdır; buna rağmen `Belge` sırasında `Zamanli`'den hemen sonra gelen sınıf
`Kayit` değil, **`Imzali`**'dir. Sıra ağaçta yukarı doğru tek dal izlemez; bir sınıfı geçince
o dalın tabanına atlamaz, **ortak tabanı en sona bırakır.**

Bu kuralın gerekçesi ilk ölçümde duruyor. Sıra `Belge -> Zamanli -> Kayit -> Imzali` olsaydı
`kaynak` araması `Kayit`'te dururdu ve `Imzali`'nin yazdığı gövde hiç bulunamazdı — bir
kardeşin yeniden yazdığı yöntem, öteki kardeşin tabanı yüzünden kaybolurdu. Ortak taban en
sona alınarak bu kayıp önlenir: taban ancak **bütün** türevleri denendikten sonra sorulur.
Sıranın iki kuralı bu yüzden bir üslup tercihi değil, çoklu kalıtımın anlamlı olmasının
koşuludur.

## `super()` Ataya Değil, Sıraya Gider

Bunun en görünür sonucu `super()` çağrısındadır. Adı bir "üst sınıf" çağrısı gibi okunur ama
yaptığı iş budur değildir: `super()`, **çağrıyı yapan nesnenin çözümleme sırasında**, gövdenin
yazıldığı sınıftan **hemen sonraki** sınıfa gider. Gövde aynı kalır, sıra değişir, gidilen yer
değişir.

- **SN23** — Ölçüm için dört yeni sınıf kurulur; ortak kurgunun ağacına dokunulmaz.
- **SN24** — Dört sınıfın dördü de aynı adı yazar ve gövdesi tek satırdır: kendi adını listeye
  koyup `super()` üzerinden zinciri sürdürür. Taban sınıf zinciri kapatır.
- **SN25** — Ölçülen şey çağrının sonucu değil, **koşan gövdelerin dizisidir**; sayı gövde
  sayısıdır.
- **SN26** — İkinci tablo `SolKatman`'ın gövdesini iki ayrı örnek üzerinden okur; gövde tek,
  örnekler iki ayrı sınıftandır.

```python
class Katman:
    def etiket(self):
        return ["Katman"]


class SolKatman(Katman):
    def etiket(self):
        return ["SolKatman"] + super().etiket()


class SagKatman(Katman):
    def etiket(self):
        return ["SagKatman"] + super().etiket()


class Birlesik(SolKatman, SagKatman):
    def etiket(self):
        return ["Birlesik"] + super().etiket()


def sonraki(sinif, govde):
    """Govdesi 'govde' sinifinda yazili super() cagrisi kime gider?"""
    m = sinif.__mro__
    return m[m.index(govde) + 1].__name__


print(f"{'örneğin sınıfı':<12s} {'koşan gövde':>11s}  zincir")
for s in (SolKatman, Birlesik):
    z = s().etiket()
    print(f"{s.__name__:<12s} {len(z):>11d}  {' -> '.join(z)}")

print()
print(f"{'gövdeyi yazan':<14s} {'örneğin sınıfı':<14s} super() kime gider")
for s in (SolKatman, Birlesik):
    print(f"{'SolKatman':<14s} {s.__name__:<14s} {sonraki(s, SolKatman)}")
```

```
örneğin sınıfı koşan gövde  zincir
SolKatman              2  SolKatman -> Katman
Birlesik               4  Birlesik -> SolKatman -> SagKatman -> Katman

gövdeyi yazan  örneğin sınıfı super() kime gider
SolKatman      SolKatman      Katman
SolKatman      Birlesik       SagKatman
```

`SolKatman` gövdesi iki ölçümde de **aynıdır** ve tek satırdır. Bir `SolKatman` örneğinde o
satırdaki `super()` çağrısı `Katman`'a gider ve zincir **2** gövdede biter. Bir `Birlesik`
örneğinde aynı satır **`SagKatman`**'a gider — `SolKatman`'ın tabanı olmayan, gövdesinde adı
bile geçmeyen bir sınıfa — ve zincir **4** gövdede biter.

`SagKatman`'ın hiç atlanmaması bu düzenin amacıdır: çoklu kalıtımda her sınıfın gövdesi
**tam bir kez** koşar ve ortak taban en sonda **bir kez** çalışır. Zincirin işlemesi için her
halkanın `super()` çağırması gerekir; bir sınıf çağırmayı bıraktığında ondan sonraki bütün
gövdeler sessizce düşer. Kurulum yöntemleri de aynı zincire tabidir: `__init__` içinde
`super().__init__(...)` yazılmadığında ara sınıfların kurulum gövdeleri hiç koşmaz ve eksiklik
ancak eksik alan okunduğunda ortaya çıkar.

Zincirin ikinci koşulu imzalardır. Bir gövde `super()` üzerinden kime gideceğini bilmediğine
göre, aynı adı taşıyan bütün gövdelerin **birbirini kabul eden** parametrelerle yazılmış olması
gerekir. `SolKatman` gövdesini yazan taraf `SagKatman`'ı hiç görmemiş olabilir; buna rağmen
ikisi aynı çağrıda yan yana koşar. Bileşimde böyle bir örtük sözleşme yoktur — `Sarmal.__init__`
içerideki iki nesneyi adlarıyla ve argümanlarıyla açıkça var eder, gidilecek yer sıraya değil
gövdeye yazılıdır.

Buradan tasarım tarafındaki sonuç çıkar. Bir gövdeyi doğru okumak için o gövdenin bulunduğu
sınıfı bilmek yetmez; **çağrının hangi nesneden geldiğini** de bilmek gerekir. Bileşimde böyle
bir bilinmez yoktur: `Sarmal.bicimle` gövdesindeki çağrı `self.imzali`'ye gider ve o ad
gövdenin içinde yazılıdır. Kalıtım kısa yazım verir ve yanıtlayanı gizler; bileşim uzun yazım
ister ve yanıtlayanı yazar.

Gizlenen şeyin okunamaz olmadığını da eklemek gerekir. Çözümleme sırası bir tahmin değil,
sınıfın üzerinde duran ve okunabilen bir listedir; `saglayan` işlevi o listeyi gezen üç
satırdır. Bir yeteneğin gövdesini arayan biri sınıf ağacını gözle izlemek zorunda değildir,
sırayı doğrudan sorabilir. Kalıtımın bedeli bilginin **yok olması** değil, çağrıyı okuyan
kişinin onu ayrıca sorması gerekmesidir.

## Özet

- Bir yeteneği hangi sınıfın yanıtladığını **yöntem çözümleme sırası** belirler; ad birden çok
  sınıfta yazılıysa sırada ilk gelen kazanır ve ötekiler hiç çağrılmaz.
- `Belge` dört yeteneğin **0**'ını kendi gövdesinde taşır, yanıt üç ayrı sınıftan gelir;
  `Sarmal` aynı dört yeteneğin **4**'ünü de kendi gövdesinde yazar.
- `bicimle` gövdesi `Kayit`'te yazılıdır ama içindeki çağrı `self` üzerinden çözüldüğü için
  sonuç **`<Imzali>`** çıkar: gövdeyi okumak sonucunu söylemez.
- Çözümleme sırası iki kuralla kurulur — her sınıf tabanlarından önce, tabanlar yazıldıkları
  sırayla. Dört taban sıralamasının **üçü** kurulur, kural sağlanamayan **biri** tanım anında
  `TypeError` ile düşer.
- `super()` gövdenin yazıldığı sınıfın tabanına değil, **örneğin sırasında** o sınıftan sonra
  gelene gider: aynı `SolKatman` gövdesi bir örnekte `Katman`'a, ötekinde `SagKatman`'a gider
  ve zincir **2**'ye karşı **4** gövde koşar.

## Sonraki Adım

Buraya kadar bütün adlar dışarıdan görünür kabul edildi: `Belge` örneğinin `kaynak`'ı da,
`Sarmal`'ın içinde tuttuğu `imzali` nesnesi de aynı biçimde okunabilir. Oysa `imzali`,
`Sarmal`'ın iç düzenidir; dışarıdan ona dokunan bir kod, `Sarmal`'ın yarın değiştirebileceği
bir ayrıntıya bağlanmış olur. İki tasarımın ayrıldığı yerlerden biri de budur: kalıtımda taban
sınıfın her adı türeve olduğu gibi geçer, bileşimde dışarıya ne verileceği gövdede tek tek
yazılır. Sonraki ders bu ayrımın Python'da nasıl bildirildiğini ölçer:
adın başına konan alt çizgi erişimi gerçekten **engelliyor** mu, iki alt çizgi ne değiştiriyor,
ve engellemiyorsa bu bildirimin ölçülebilir bir işi var mı?
