---
title: 'Özel Yöntemler'
source: 'https://academia.sh/tr/kurslar/python-nesne-ve-tipler/ozel-yontemler'
course: 'Nesneye Dayalı Python ve Tipler'
language: tr
updated: '2026-08-17T18:10:30+00:00'
license: 'CC BY-SA 4.0'
---

# Özel Yöntemler

Hiçbir özel yöntem yazmayan sınıf on bir sözdizim biçiminin 5'ine katılır ama hiçbirini kendisi yanıtlamaz; `__eq__` yazmak `__hash__` adını boşaltır ve tek yöntem iki sözdizimi birden kapatır.

Önceki üç ders sınıfları kendi yazdığımız yöntemlerle çağırdı: `ekle`, `bicimle`, `kaynak`.
Oysa Python Temelleri kursu sözdizimin bir kısaltma olduğunu ölçmüştü — `n + m` bir yöntem
çağrısıdır, `x in n` bir yöntem çağrısıdır, `for` bir protokoldür. **O listeler
tekrarlanmaz.** Orada ölçülen taraf **çağıran** taraftı ve karşılayan taraf hep hazırdı:
liste, dizgi, sözlük, üreteç. Katılan nesneleri dil vermişti.

Bu ders karşılayan tarafı bizim yazdığımız durumu ölçer. İki soru vardır. Birincisi: hiçbir
özel yöntem yazmayan bir sınıf bu sözdizimlerin kaçına katılabilir, ve katıldıklarında **yanıtı
kim veriyor**? İkincisi: yazdığımız her yöntem bir sözdizim açar da, hiç kapatır mı?

## Yazmayan Sınıf Ne Yapabiliyor

On bir sözdizim biçimi seçilir; her biri belli bir özel yöntem adını arar. İki sınıf aynı
veriyi taşır. `Ciplak` hiçbir özel yöntem yazmaz. `Yazili` on bir yöntemin on birini de yazar.
Ölçüm iki şeyi ayrı ayrı sorar: sözdizim **çalıştı mı**, ve o adı **hangi sınıf sağlıyor**.
İki sorunun ayrı sorulması gerekir, çünkü yanıtları her satırda aynı çıkmaz — bir sözdizim
çalışmadan da adı bulunmuş olabilir, bulunmadan da çalışmış olabilir.

- **SN42** — İki sınıf aynı üç öğeyi taşır ve `__init__` gövdeleri birbirinin aynısıdır;
  aralarındaki tek fark yazılan özel yöntemlerdir. `Yazili` `Ciplak`'tan türemez.
- **SN43** — Her biçim iki taze örnek üzerinde çalıştırılır; ölçüm sonucun değerine değil,
  çağrının karşılanıp karşılanmadığına bakar. Karşılanmayan çağrı `TypeError` ile düşer.
- **SN44** — "Yanıtlayan" sütunu adı çözümleme sırasında ilk taşıyan sınıfı verir; hiçbir sınıf
  taşımıyorsa `None` yazılır.
- **SN45** — Hiçbir sözdizimin **sonucu basılmaz**. `Ciplak` bir temsil yöntemi yazmadığı için
  varsayılan temsili **ortama bağlı veri taşır**; ölçüm bu yüzden yalnız durum ve yanıtlayan
  sınıf basar.

```python
"""Sozdizime katilan tarafi biz yaziyoruz: yazmayan ve yazan iki sinif."""


def saglayan(sinif, ad):
    for s in sinif.__mro__:
        if ad in s.__dict__:
            return s.__name__
    return None


class Ciplak:
    """Hicbir ozel yontem yazmaz; yalnizca ogelerini tasir."""

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


class Yazili:
    """Ayni veriyi tasir, katildigi her sozdizim icin bir yontem yazar."""

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

    def __repr__(self):
        return f"Yazili({self.ogeler})"

    def __str__(self):
        return "-".join(str(x) for x in self.ogeler)

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

    def __eq__(self, o):
        return isinstance(o, Yazili) and self.ogeler == o.ogeler

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

    def __bool__(self):
        return bool(self.ogeler)

    def __contains__(self, x):
        return x in self.ogeler

    def __iter__(self):
        return iter(self.ogeler)

    def __enter__(self):
        return self

    def __exit__(self, *k):
        return False

    def __getitem__(self, i):
        return self.ogeler[i]

    def __hash__(self):
        return hash(tuple(self.ogeler))


def girdi(n):
    with n:
        return True


BICIMLER = (
    ("repr(n)", "__repr__", lambda n, m: repr(n)),
    ("str(n)", "__str__", lambda n, m: str(n)),
    ("len(n)", "__len__", lambda n, m: len(n)),
    ("n == m", "__eq__", lambda n, m: n == m),
    ("n < m", "__lt__", lambda n, m: n < m),
    ("bool(n)", "__bool__", lambda n, m: bool(n)),
    ("2 in n", "__contains__", lambda n, m: 2 in n),
    ("for x in n", "__iter__", lambda n, m: [x for x in n]),
    ("with n", "__enter__", lambda n, m: girdi(n)),
    ("n[0]", "__getitem__", lambda n, m: n[0]),
    ("hash(n)", "__hash__", lambda n, m: hash(n)),
)


def olc(sinif, islev):
    try:
        islev(sinif(), sinif())
    except TypeError:
        return "düştü"
    return "çalıştı"


print(f"{'sözdizim':<12s} {'özel yöntem':<14s} {'Ciplak':>8s} "
      f"{'yanıtlayan':>11s} {'Yazili':>8s} {'yanıtlayan':>11s}")
for ad, yontem, islev in BICIMLER:
    print(f"{ad:<12s} {yontem:<14s} {olc(Ciplak, islev):>8s} "
          f"{str(saglayan(Ciplak, yontem)):>11s} {olc(Yazili, islev):>8s} "
          f"{str(saglayan(Yazili, yontem)):>11s}")

for sinif in (Ciplak, Yazili):
    calisan = sum(1 for _, _, f in BICIMLER if olc(sinif, f) == "çalıştı")
    kendi = sum(1 for _, y, _ in BICIMLER if saglayan(sinif, y) == sinif.__name__)
    print(f"\n{sinif.__name__}: çalışan {calisan}/{len(BICIMLER)}, "
          f"yanıtı kendi veren {kendi}/{len(BICIMLER)}")
```

```
sözdizim     özel yöntem      Ciplak  yanıtlayan   Yazili  yanıtlayan
repr(n)      __repr__        çalıştı      object  çalıştı      Yazili
str(n)       __str__         çalıştı      object  çalıştı      Yazili
len(n)       __len__           düştü        None  çalıştı      Yazili
n == m       __eq__          çalıştı      object  çalıştı      Yazili
n < m        __lt__            düştü      object  çalıştı      Yazili
bool(n)      __bool__        çalıştı        None  çalıştı      Yazili
2 in n       __contains__      düştü        None  çalıştı      Yazili
for x in n   __iter__          düştü        None  çalıştı      Yazili
with n       __enter__         düştü        None  çalıştı      Yazili
n[0]         __getitem__       düştü        None  çalıştı      Yazili
hash(n)      __hash__        çalıştı      object  çalıştı      Yazili

Ciplak: çalışan 5/11, yanıtı kendi veren 0/11

Yazili: çalışan 11/11, yanıtı kendi veren 11/11
```

`Ciplak` on bir biçimin **5**'ine katılıyor ve yanıtı kendi veren biçim sayısı **0**. Yazmamak
sözdizimi kapatmaz; **sessiz bir varsayılana bırakır.** Çalışan beş satırın dördünde yanıtı
bütün sınıfların ortak tabanı veriyor, `bool(n)` satırında ise hiçbir sınıf vermiyor — orada
sözdizim bir yöntem bulamadığında düşmek yerine "her nesne doğrudur" kuralına geçiyor.

Varsayılanların ne söylediği önemlidir, çünkü hepsi **kimliğe** dayanır. Ortak tabanın verdiği
eşitlik iki ayrı nesneyi eşit saymaz; verdiği karma değeri de kimlikten üretilir. `Ciplak`
öğeleriyle karşılaştırılmak ya da öğeleriyle anahtar olmak isterse bu varsayılanlar yanlış
yanıt verir — hata vermezler, **yanlış yanıt** verirler. Bir hatanın en pahalı biçimi budur:
aynı içeriği taşıyan iki `Ciplak` nesnesi bir kümeye konduğunda iki ayrı öğe sayılır ve program
hiçbir uyarı vermeden çalışmaya devam eder.

`n < m` satırı ayrı bir okumadır. Yanıtlayan sütunu boş değil, ortak tabanı gösteriyor; ad
bulundu. Buna rağmen sözdizim **düştü**. Ortak taban bu adı tanımlar ama gövdesi "bu işi
bilmiyorum" der ve karşılaştırma karşılıksız kalır. **Adın bulunması yanıtın verildiği anlamına
gelmez.** Bir yeteneği aramanın doğru yolu adın varlığına bakmak değil, çağrının karşılanıp
karşılanmadığına bakmaktır.

`Yazili` on bir biçimin on birine katılıyor ve on birinin de yanıtını kendisi veriyor. Bir
sınıfın "dilin nesnelerine benzemesi" ayrı bir yetenek değildir; **yazılan yöntemlerdir.**
Katılım tipin adından ya da tabanından değil, sınıfın sözlüğüne konan adlardan gelir.

Sayının bir ayrıntısı tabloda görünmüyor. `Yazili` on bir sözdizim için **on iki** gövde
yazar: bağlam sözdizimi tek satırdır ama girişi ve çıkışı ayrı iki yöntemle karşılanır, ve
tablo yalnız girişi listeler. Sözdizim ile yöntem arasındaki eşleme birebir değildir; bir
sözdizim birden çok gövde isteyebilir, `bool(n)` satırında görüldüğü gibi hiç gövde
istemeyebilir de.

Yazılan yöntemlerin bazıları kendilerine bitişik sözdizimleri de açar. Eşitliği yazan sınıf
eşitsizliği ayrıca yazmaz; küçüklüğü yazan sınıf, aynı tipten iki nesne arasında büyüklük
karşılaştırmasını da karşılar, çünkü dil işlemi ters çevirip öteki işlenene sorar. Bunlar
Python Temelleri kursunda **çağıran** taraftan ölçülmüştü; burada aynı düşüşlerin **yazan**
taraftaki karşılığı görülüyor — bir gövde yazmak, o gövdeye düşen bütün yazımları birden
karşılamaktır.

## Bir Yöntem Yazmak Bir Sözdizimi Kapatabilir

Yazılan yöntemler yalnız kapı açmaz. Eşitlikle karma değeri arasında dilin sürdürdüğü bir
sözleşme vardır: eşit sayılan iki nesnenin karma değeri de eşit olmalıdır. Bir sınıf eşitliği
kendisi tanımladığında bu sözleşme kendiliğinden sağlanamaz hâle gelir ve dil kararı sınıfa
bırakmaz — karma yeteneğini **kaldırır**.

- **SN46** — Üç sınıf aynı tek alanı taşır; farkları yalnız hangi yöntemi yazdıklarıdır.
  Üçüncü sınıf ikincisinden türer ve yalnız karma yöntemini ekler.
- **SN47** — Karma sınaması değerin kendisini basmaz, yalnız çağrının karşılanıp
  karşılanmadığını bildirir; **karma değeri ortama bağlı olabilir.**
- **SN48** — Son iki sütun `__hash__` adının sınıfın kendi sözlüğünde bulunup bulunmadığını ve
  değerinin boş olup olmadığını ayrı ayrı gösterir.

```python
class Yalin:
    """Ne esitlik ne karma yazar."""

    def __init__(self, deger=1):
        self.deger = deger


class Esit:
    """Yalniz esitligi yazar."""

    def __init__(self, deger=1):
        self.deger = deger

    def __eq__(self, o):
        return isinstance(o, Esit) and self.deger == o.deger


class EsitVeKarma(Esit):
    """Esitligi devralir, karmayi kendisi yazar."""

    def __hash__(self):
        return hash(self.deger)


def dene(islev):
    try:
        return str(islev())
    except TypeError as e:
        return f"!{type(e).__name__}"


print(f"{'sınıf':<13s} {'a == b':>8s} {'hash(a)':>16s} {'anahtar olma':>16s} "
      f"{'__hash__ yazılı':>16s} {'değeri boş':>11s}")
for sinif in (Yalin, Esit, EsitVeKarma):
    a, b = sinif(), sinif()
    print(f"{sinif.__name__:<13s} {dene(lambda: a == b):>8s} "
          f"{dene(lambda: hash(a) is not None):>16s} "
          f"{dene(lambda: len({a: 1})):>16s} "
          f"{str('__hash__' in sinif.__dict__):>16s} "
          f"{str(sinif.__hash__ is None):>11s}")
```

```
sınıf           a == b          hash(a)     anahtar olma  __hash__ yazılı  değeri boş
Yalin            False             True                1            False       False
Esit              True       !TypeError       !TypeError             True        True
EsitVeKarma       True             True                1             True       False
```

İlk satır varsayılan durumu gösteriyor: iki ayrı nesne eşit değil, ama karma değeri var ve
nesne bir kapta anahtar olabiliyor. İkinci satırda tek bir yöntem yazıldı ve **iki** sözdizim
birden kapandı — hem `hash(a)` hem anahtar olma düştü. Yazılan yöntem `__eq__`'dı; kapanan
sözdizimlerin ikisi de `__hash__`'e bağlıydı.

Son iki sütun bunun nasıl olduğunu söylüyor. `Esit` sınıfının kendi sözlüğüne `__hash__` adı
**yazılmıştır** ve değeri **boştur**. Dil, eşitliği yazan sınıfa sessizce bir giriş ekler ve o
girişi boş bırakır; arama artık ortak tabana ulaşamaz, ilk adımda boş bir değere çarpar. Bu bir
yan etki değil, bilinçli bir karardır: eşitliğini değiştirmiş bir nesnenin eski karma değerini
kullanması, onu bir kapta **kaybolmuş** bir anahtar hâline getirirdi.

Üçüncü satır çözümü gösteriyor. `EsitVeKarma` eşitliği devralır ve karmayı kendisi yazar; giriş
artık boş değildir ve iki sözdizim de geri açılır. Kural şudur: **eşitliği yazan sınıf karmayı
da yazar** — ya da yazmayarak nesnenin anahtar olamayacağını kabul eder. Karma yazılırken
eşitlikte kullanılan aynı alanların kullanılması gerekir, yoksa sözleşme yine bozulur.

Sözleşmenin ikinci yarısı da yazan tarafın sorumluluğundadır: karma değeri nesnenin **ömrü
boyunca** değişmemelidir. Eşitliği değiştirilebilir bir alandan üreten bir sınıf, o alanı bir
kapta anahtarken değiştirdiğinde nesneyi kendi kabında bulunamaz hâle getirir. Bu yüzden
karmalanabilir olması istenen sınıfların eşitliği **değiştirilmeyen** alanlardan üretmesi
beklenir. `Yazili`'nin ilk ölçümdeki karma gövdesinin öğeleri bir demete çevirmesi de bu
nedenledir: değiştirilebilir bir kabın kendisi karmalanamaz.

## İki Temsil

Kalan ayrım iki temsil yöntemi arasındadır. İkisi de nesneden bir dizgi üretir ama hedefleri
ayrıdır: biri **çözümleyici** için nesneyi tanıtır, öteki **okuyucu** için nesneyi sunar.
Hangisinin çağrıldığını kullanım yeri belirler.

- **SN49** — İki sınıf aynı iki dizgiyi döndürür; farkları yalnız birinin metin yöntemini
  yazmamasıdır.
- **SN50** — Altı kullanım biçimi denenir ve her biri taze bir örnek üzerinde çalışır; ölçüm
  dönen dizginin **hangisi** olduğuna bakar.
- **SN51** — Son satırlar altı biçimden kaçının metin yöntemine gittiğini sayar; kap içindeki
  basım da bu sayıya dahildir.

```python
class YalnizTemsil:
    """Yalniz __repr__ yazar."""

    def __repr__(self):
        return "temsil"


class IkiTemsil:
    """Ikisini de yazar."""

    def __repr__(self):
        return "temsil"

    def __str__(self):
        return "metin"


KULLANIM = (
    ("str(n)", lambda n: str(n)),
    ("repr(n)", lambda n: repr(n)),
    ("f-dizgide n", lambda n: f"{n}"),
    ("f-dizgide n!r", lambda n: f"{n!r}"),
    ("[n] basımı", lambda n: str([n])),
    ("biçimlendirme", lambda n: "{}".format(n)),
)

print(f"{'yazım':<15s} {'yalnız __repr__ yazan':>22s} {'ikisini de yazan':>18s}")
for ad, islev in KULLANIM:
    print(f"{ad:<15s} {islev(YalnizTemsil()):>22s} {islev(IkiTemsil()):>18s}")

for sinif in (YalnizTemsil, IkiTemsil):
    metin = sum(1 for _, f in KULLANIM if "metin" in f(sinif()))
    print(f"\n{sinif.__name__}: __str__ sonucunu veren yazım {metin}/{len(KULLANIM)}")
```

```
yazım            yalnız __repr__ yazan   ikisini de yazan
str(n)                          temsil              metin
repr(n)                         temsil             temsil
f-dizgide n                     temsil              metin
f-dizgide n!r                   temsil             temsil
[n] basımı                    [temsil]           [temsil]
biçimlendirme                   temsil              metin

YalnizTemsil: __str__ sonucunu veren yazım 0/6

IkiTemsil: __str__ sonucunu veren yazım 3/6
```

Sol sütunda altı yazımın altısı da aynı sonucu veriyor ve metin yöntemine giden yazım **0**.
Metin yöntemi yazılmadığında istek karşılıksız kalmaz, **temsil yöntemine düşer**. Bu düşüşün
yönü tek taraflıdır: temsil yöntemi yazılmadığında metin yöntemine düşüş **yoktur**. İki
yöntemden yalnız biri yazılacaksa yazılacak olan **temsildir**.

Sağ sütunda altı yazımın **3**'ü metin yöntemine gidiyor. Ayrım açık: dizgiye çevirme ve
biçimlendirme okuyucuya sunar, açık istek ve dönüştürme işareti çözümleyiciye tanıtır. Beşinci
satır en çok şaşırtan yerdir — nesne bir kabın içindeyken **her zaman** temsil yöntemiyle
basılır, kap dışarıdan metne çevrilmiş olsa bile. Kap kendi metnini üretirken içindeki her
öğeden temsil ister, çünkü çözümleyicinin göreceği şey öğenin sunumu değil, kimliğidir.

Buradan yazım kuralı çıkar: temsil yöntemi nesneyi **yeniden kurabilecek** kadar bilgi
taşımalıdır; metin yöntemi ise okunabilir olmalıdır. `Yazili` sınıfının ilk ölçümdeki iki
gövdesi tam olarak bu ayrımı izler: temsil gövdesi sınıfın adını ve öğelerini birlikte verir,
metin gövdesi yalnız öğeleri okunabilir biçimde dizer.

Bu ayrımın hata ayıklamadaki karşılığı doğrudan ölçülebilir bir kolaylıktır. Bir kapta duran
yüz nesnenin dökümü alındığında görülecek olan şey, o sınıfın temsil gövdesidir; temsil
yazılmamışsa döküm yüz satır boyunca hiçbir şey söylemez. Yazılan tek bir gövde, nesnenin
göründüğü **bütün** kaplarda okunabilirlik kazandırır.

## Özet

- Hiçbir özel yöntem yazmayan sınıf on bir sözdizimin **5**'ine katılır ve **0**'ının yanıtını
  kendisi verir; yazmamak sözdizimi kapatmaz, sessiz bir varsayılana bırakır ve varsayılanların
  hepsi kimliğe dayanır.
- Ad bulunmuş olması yanıtın verildiği anlamına gelmez: `n < m` için ortak tabanda bir ad
  vardır ama sözdizim yine de düşer.
- On bir yöntemi yazan sınıf on bir sözdizimin tamamına katılır ve tamamının yanıtını kendisi
  verir; katılım tipin adından değil, yazılan yöntemlerden gelir.
- Bir yöntem yazmak bir sözdizimi kapatabilir: `__eq__` yazan sınıfın sözlüğüne `__hash__` adı
  **boş** olarak eklenir ve karma ile anahtar olma birlikte düşer. Eşitliği yazan sınıf karmayı
  da yazar.
- Metin yöntemi yazılmadığında istek temsil yöntemine düşer, tersi olmaz; ikisini de yazan
  sınıfta altı yazımın **3**'ü metne gider ve kap içindeki basım her zaman temsili kullanır.

## Sonraki Adım

Bu derste yazılan her yöntem bir **çağrıyla** tetiklendi: `len(n)` yazıldığında bir gövde
koştu, `n[0]` yazıldığında bir gövde koştu. Öznitelik okumak ise hiçbir gövdeyi
çalıştırmıyordu — `n.ogeler` bir sözlük aramasıydı ve araya kimse girmiyordu. Üçüncü dersin
bıraktığı açık tam buradaydı: değişmezi koruyan gövdeye uğramayan yazma denetimsiz kalıyordu.
Sonraki ders erişimin kendisini araya bir gövde koyarak yakalamayı ölçer: aynı sayıda okuma ve
yazma, doğrudan alanla kaç gövde çalıştırır, araya giren bir tanımla kaç gövde çalıştırır, ve
araya giren kod verisini nerede tutarsa üç örnek tek değeri paylaşmaya başlar?
