---
title: 'Tip Dönüşümü'
source: 'https://academia.sh/tr/kurslar/python-temelleri/tip-donusumu'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:28+00:00'
license: 'CC BY-SA 4.0'
---

# Tip Dönüşümü

Dönüşüm yerleşikleri sekiz yazımda ayrı özel yöntemler çağırır ve karşılığı olmayan iki yazım düşer; yirmi dizgi denemesinde 7 `ValueError` ile 4 `TypeError` ayrılır ve sayısal yükseltmenin sihir olmadığı `NotImplemented` ile gösterilir.

Önceki ders `str(n)` yazımının `__str__` çağırdığını ölçtü: bir nesneyi metne çevirmek de
bir protokol çağrısıymış. Aynı soru ters yönde de sorulabilir. `int(n)` yazıldığında ne
çağrılıyor, `float(n)` nesneden neyi istiyor ve karşılığı olmayan bir dönüşüm istendiğinde
ne oluyor?

Programlama Temelleri kursu açık ve örtük dönüşümü, kayıplı daraltmayı ve dış girdiyi
dönüştürmeden önce doğrulamayı zaten kurmuştu; gerçel sayıdan tam sayıya geçişin
yuvarlamayıp kestiği de orada gösterildi. **Bunlar tekrarlanmaz.** Burada ölçülen şey
dönüşümün **düzeneğidir**: hangi yerleşik hangi adı arıyor, aradığını bulamazsa hangi
istisnayı fırlatıyor ve iki ayrı sayısal tip toplandığında dilin yaptığı şey gerçekten bir
"dönüşüm" mü?

## Dönüşüm de Bir Protokol Çağrısıdır

`int`, `float`, `str` ve `list` birer yerleşik işlevdir ve hepsi aynı biçimde çalışır:
verilen nesneden belli adı taşıyan bir yöntem isterler. Ad yoksa dönüşüm de yoktur.

- **DT39** — Ölçülen nesne dört dönüşüm protokolüne birden katılır ve her katılımını
  kaydeder; kayıttaki ünlem önekli öğe bir çağrıyı değil, bir istisnayı gösterir.
- **DT40** — İki karşı örnek kullanılır: hiçbir dönüşüm yöntemi tanımlamayan bir nesne ve
  yalnız `__int__` tanımlayıp dizin protokolünü taşımayan bir nesne.
- **DT41** — Dizinleme ölçümünde beş harfli sabit bir dizgi kullanılır; dönen harf,
  nesnenin dizin olarak verdiği sayıya bağlıdır.

```python
"""Donusum yerlesikleri hangi ozel yontemi cagiriyor?"""

KAYIT = []


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


class Olcum:
    """Donusum protokollerine katilir ve her katilimini kaydeder."""

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

    def __int__(self):
        kaydet("__int__")
        return sum(self.ogeler)

    def __float__(self):
        kaydet("__float__")
        return float(sum(self.ogeler))

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

    def __index__(self):
        kaydet("__index__")
        return len(self.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


class Sade:
    """Hicbir donusum yontemi tanimlamaz."""


class YalnizTamSayi:
    """Yalniz __int__ tanimlar; dizin protokolunu tasimaz."""

    def __int__(self):
        kaydet("__int__")
        return 2


def olc(islev):
    KAYIT.clear()
    try:
        sonuc = repr(islev())
    except Exception as e:
        KAYIT.append(f"!{type(e).__name__}")
        sonuc = "—"
    return list(KAYIT), sonuc


BICIMLER = (
    ("int(n)", lambda: int(Olcum())),
    ("float(n)", lambda: float(Olcum())),
    ("str(n)", lambda: str(Olcum())),
    ("list(n)", lambda: list(Olcum())),
    ("'kuzey'[n]", lambda: "kuzey"[Olcum((1, 2))]),
    ("int(Sade())", lambda: int(Sade())),
    ("'kuzey'[m]", lambda: "kuzey"[YalnizTamSayi()]),
    ("int(m)", lambda: int(YalnizTamSayi())),
)

print(f"{'yazım':<14s} {'çağrı':>5s} {'protokol':<32s} sonuç")
for ad, islev in BICIMLER:
    c, sonuc = olc(islev)
    print(f"{ad:<14s} {len(c):5d} {' '.join(c):<32s} {sonuc}")
```

```
yazım          çağrı protokol                         sonuç
int(n)             1 __int__                          6
float(n)           1 __float__                        6.0
str(n)             1 __str__                          'olcum [1, 2, 3]'
list(n)            5 __iter__ __next__ __next__ __next__ __next__ [1, 2, 3]
'kuzey'[n]         1 __index__                        'z'
int(Sade())        1 !TypeError                       —
'kuzey'[m]         1 !TypeError                       —
int(m)             1 __int__                          2
```

İlk üç satır kuralı kuruyor: `int` yerleşiği `__int__`, `float` yerleşiği `__float__`, `str`
yerleşiği `__str__` çağırıyor. Yerleşiğin adı ile yöntemin adı arasındaki karşılık tesadüf
değil, sözleşmedir. Dönüşümü yapan şey yerleşik değildir — yerleşik yalnız **kimin
yapacağını bilir**; işi nesnenin kendisi yapar ve sonucu döndürür.

Dördüncü satır bir dönüşümü daha ayırıyor. `list(n)` bir `__list__` yöntemi aramaz; **yineleme
protokolünü** kullanır ve öğeleri tek tek toplayarak yeni bir liste kurar. Üç öğe için
**5** çağrı ödeniyor: bir `__iter__` ve dört `__next__` — ilk dersteki "öğe sayısından bir
fazla" örüntüsünün aynısı. Buradan genel kural çıkar: bir koleksiyona dönüşüm ayrı bir
protokol istemez, var olanın üzerine kurulur. Aynı gerekçeyle `tuple(n)` ve `set(n)` de
yeni bir yöntem aramaz; üçü de aynı yineleme protokolünü tüketir ve yalnız kurdukları kabın
tipiyle ayrılırlar.

Beşinci satır ile yedinci satır birlikte okunmalı. Bir nesnenin dizin olarak kullanılması
`__int__` değil, **`__index__`** ister. İkisi ayrı sözleşmelerdir: `__int__` "bu nesne bir
tam sayıya **çevrilebilir**" demektir, `__index__` "bu nesne zaten bir tam sayı **konumdur**"
demektir. Ayrım keyfi değildir — bir gerçel sayı `__int__` taşır ama dizin olamaz, çünkü
dizinlemede kesme yapmak sessiz bir kusur olurdu. Yalnız `__int__` tanımlayan nesne son iki
satırda tam olarak bunu gösteriyor: `int(m)` çalışıyor, `'kuzey'[m]` `TypeError` ile düşüyor.

Altıncı satır ise ilk dersteki sonucun aynısı. Hiçbir dönüşüm yöntemi tanımlamayan nesnede
`int` çağrısı `TypeError` fırlatıyor. Sekiz yazımın **6**'sı bir yöntem buluyor, **2**'si
bulamıyor ve düşüyor. **Dönüşüm bir hak değil, bir yöntem meselesidir.**

## Başarısız Dönüşüm Bir İstisnadır

Yukarıdaki tablo nesneden sayıya dönüşümü ölçtü. Dış dünyadan gelen veri ise dizgidir ve
orada durum ayrıdır: `str` tipi `__int__` tanımlamaz. `int("12")` yazıldığında yapılan şey
bir protokol çağrısı değil, metnin **çözümlenmesidir** — ve çözümleme başarısız olabilir.

- **DT42** — On girdi denenir: sekizi dizgi, ikisi başka tiptendir. Her girdi hem `int` hem
  `float` ile denenir; ölçülen şey dönen değer ya da istisnanın **türüdür**.
- **DT43** — Sayım yalnız istisnaları toplar; başarılı dönüşümler sayıma girmez.

```python
"""Basarisiz donusum: hangi girdi hangi istisnayi uretir?"""

GIRDILER = ("12", " 12 ", "+12", "1_2", "12.5", "", "kuzey", "0x1f", None, [1])


def dene(islev, girdi):
    try:
        return repr(islev(girdi)), "—"
    except Exception as e:
        return "—", type(e).__name__


print(f"{'girdi':<10s} {'int(...)':>10s} {'istisna':<12s}"
      f" {'float(...)':>12s} {'istisna':<12s}")
sayim = {}
for g in GIRDILER:
    i_deger, i_hata = dene(int, g)
    f_deger, f_hata = dene(float, g)
    for h in (i_hata, f_hata):
        if h != "—":
            sayim[h] = sayim.get(h, 0) + 1
    print(f"{repr(g):<10s} {i_deger:>10s} {i_hata:<12s}"
          f" {f_deger:>12s} {f_hata:<12s}")

print(f"\ntoplam deneme {2 * len(GIRDILER)}, "
      + ", ".join(f"{h} {n}" for h, n in sorted(sayim.items())))
print("taban verilirse:", "int('0x1f', 16) ->", int("0x1f", 16))
```

```
girdi        int(...) istisna        float(...) istisna     
'12'               12 —                    12.0 —           
' 12 '             12 —                    12.0 —           
'+12'              12 —                    12.0 —           
'1_2'              12 —                    12.0 —           
'12.5'              — ValueError           12.5 —           
''                  — ValueError              — ValueError  
'kuzey'             — ValueError              — ValueError  
'0x1f'              — ValueError              — ValueError  
None                — TypeError               — TypeError   
[1]                 — TypeError               — TypeError   

toplam deneme 20, TypeError 4, ValueError 7
taban verilirse: int('0x1f', 16) -> 31
```

Yirmi denemenin **11**'i istisnayla bitiyor ve istisnalar iki türe ayrılıyor: **7**
`ValueError`, **4** `TypeError`. Ayrım rastgele değildir ve öğrenilmesi gereken şey tam
olarak budur.

**`TypeError`** girdinin **tipi** dönüştürülemediğinde doğar. `None` ve liste satırlarında
sorun değerin ne olduğu değil, o tipin sayıya çevrilecek bir yöntem taşımamasıdır — birinci
tablonun `Sade` satırıyla aynı kusur sınıfıdır. **`ValueError`** ise tip doğru ama **değer**
uygun olmadığında doğar. `'kuzey'` bir dizgidir ve dizgi sayıya çevrilebilir; çevrilemeyen
şey o dizginin taşıdığı metindir.

Kabul edilen girdiler de öğreticidir. Baştaki ve sondaki boşluk atılır, artı işareti kabul
edilir, alt çizgi basamak ayracı olarak okunur. Ama `'12.5'` dizgisi `int` için geçersiz,
`float` için geçerlidir: `int` bir tam sayı gösterimi bekler ve kesirli metni sessizce
kesmez. Önceki kursta ölçülen kesme davranışı **gerçel sayı nesnesinden** tam sayıya
geçişte olur, dizgiden geçişte olmaz. `'0x1f'` satırı da aynı sınıftandır; on altılık
gösterim ancak taban açıkça verildiğinde okunur ve son satır bunu gösteriyor.

Buradan çıkan kural, önceki dersin `find` ile `index` ayrımının aynısıdır: **başarısız
dönüşüm bir dönüş değeri değil, bir istisna üretir.** Hiçbir yerleşik "çeviremedim" diyen
özel bir sayı döndürmez; dönmüş olsaydı o değer gerçek bir sonuçtan ayırt edilemezdi.
Sessiz bir kusur yerine gürültülü bir istisna seçilmiştir.

Tablonun kabul sütunu bir uyarı daha taşıyor. Programlama Temelleri kursu dönüşümden önce
biçimi sınamayı iki kalıptan biri olarak vermişti; ölçüm o kalıbın sınırını gösteriyor.
Yalnız basamaklardan oluşmayı sınayan bir ön denetim `' 12 '` ve `'+12'` girdilerini
reddeder — oysa ikisi de sorunsuz çevriliyor. Ön denetimin kabul ettiği küme ile dönüşümün
kabul ettiği küme aynı değildir, ve iki kümeyi elde tutarlı kılmak dönüşüm kurallarını
ikinci kez yazmak demektir. Denemek ve düşen dönüşümü yakalamak bu yüzden daha dar bir
sözleşmedir: kabul kuralını tek bir yerde, dönüşümün kendisinde bırakır.

## Dönüşüm Tersinir mi

Başarısız dönüşüm gürültü çıkarır ve bulunur. Asıl tehlike **başarılı görünen** dönüşümdedir:
bir değer çevrilir, hiçbir istisna doğmaz ve geri çevrildiğinde eskisi çıkmaz. Programlama
Temelleri kursu bu kaybı gösterdi; burada ölçülen şey kaybın **sınırıdır** — hangi yol
güvenceli, hangisi değil.

- **DT44** — Beş tam sayı iki ayrı yoldan gidip döner: dizgi üzerinden ve gerçel sayı
  üzerinden. Ölçülen şey dönen değerin başlangıçtakine **eşit** olup olmadığıdır.
- **DT45** — Gerçel sayı ölçümünde dönüş yolu nesneyi tanıtan metin üzerinden kurulur;
  seçilen dört değer büyüklük ve kesir bakımından ayrı uçlardandır.

```python
"""Donusum tersinir mi: gidip donunce ayni deger mi?"""

TAM = (12, -3, 2 ** 53, 2 ** 53 + 1, 10 ** 23)
GERCEL = (0.1, 3.5, 1 / 3, 1e300)

print(f"{'tam sayı':<26s} {'dizgi üzerinden':>16s} {'gerçel üzerinden':>17s}")
for n in TAM:
    print(f"{n!s:<26s} {str(int(str(n)) == n):>16s} "
          f"{str(int(float(n)) == n):>17s}")

print(f"\n{'gerçel sayı':<26s} {'dizgi üzerinden':>16s}")
for x in GERCEL:
    print(f"{x!r:<26s} {str(float(repr(x)) == x):>16s}")
```

```
tam sayı                    dizgi üzerinden  gerçel üzerinden
12                                     True              True
-3                                     True              True
9007199254740992                       True              True
9007199254740993                       True             False
100000000000000000000000               True             False

gerçel sayı                 dizgi üzerinden
0.1                                    True
3.5                                    True
0.3333333333333333                     True
1e+300                                 True
```

Dizgi sütunu beş satırda da `True`. Metin üzerinden gidip dönmek tam sayıda **her zaman**
tersinirdir, çünkü üçüncü derste ölçüldüğü gibi tam sayının sabit bir genişliği yoktur:
basamak sayısı ne olursa olsun metin de o kadar uzar. Aynı güvence gerçel sayı için de
geçerlidir — alt tablonun dördü de `True`. Bir gerçel sayıyı tanıtan metin, o sayıyı geri
verecek kadar basamak taşıyacak biçimde üretilir.

Üst tablonun **gerçel üzerinden** sütunu ise ikiye ayrılıyor: ilk üç değer sorunsuz dönüyor,
son ikisi dönmüyor.
Sınır tabloda görünüyor: iki üzeri elli üç sorunsuz, onun bir fazlası değil. Nedeni,
gerçel sayı gösteriminin taşıyabileceği anlamlı basamak sayısının sınırlı olmasıdır; o
sınırın üstünde bitişik iki tam sayı aynı gerçel sayıya düşer ve geri dönüşte ikisi
ayırt edilemez. Bu, Bilgisayarlar Nasıl Çalışır kursunda kurulan gösterim sınırının Python
tarafındaki karşılığıdır. Tabloda eşitlik sınamasının `False` çıkması, dönüşümün bir
istisna fırlatmadığını da gösteriyor: iki dönüşüm de başarıyla tamamlandı, yalnız sonuç
başlangıçtaki değer değildi.

Pratik sonuç tektir: **bir tam sayı değeri korunacaksa gerçel sayıya uğratılmaz.** Ne bir
istisna doğar ne bir uyarı çıkar; yalnız bir eşitlik sınaması yanlış çıkar. Bu ders boyunca
ölçülen istisnalar bu sınıfın tam tersidir — istisna, kusuru sesli hâle getirir.

## Sayısal Yükseltme Sihir Değildir

Geriye örtük dönüşüm kalıyor. `1 + 2.5` yazıldığında tam sayı gerçel sayıya "yükseltilir" ve
sonuç gerçel çıkar. Bu, dilin sayılar için ayrı bir kural taşıdığı izlenimini verir. Ölçüm
bunun doğru olmadığını gösteriyor.

- **DT46** — İşlecin arkasındaki yöntemler doğrudan çağrılır; ölçülen şey dönen değerdir.
  Yöntem bir sonuç üretemediğinde döndürdüğü şey bir istisna değil, özel bir belirteçtir.
- **DT47** — Dört toplama denenir; ikisinde iki ayrı sayısal tip, ikisinde bir sayı ile bir
  dizgi karşılaşır.

```python
"""Sayisal yukseltme sihir degil, isleclerdeki dusustur."""

print("(1).__add__(2.5) ->", (1).__add__(2.5))
print("(2.5).__radd__(1) ->", (2.5).__radd__(1))
print("1 + 2.5 ->", 1 + 2.5, "| tipi", type(1 + 2.5).__name__)

print()
print(f"{'ifade':<14s} {'sonuç':>8s}  istisna")
for sol, sag in (("3", 4), (3, "4"), (3, 2.5), (True, 1)):
    try:
        sonuc, hata = repr(sol + sag), "—"
    except TypeError as e:
        sonuc, hata = "—", type(e).__name__
    print(f"{repr(sol) + ' + ' + repr(sag):<14s} {sonuc:>8s}  {hata}")
```

```
(1).__add__(2.5) -> NotImplemented
(2.5).__radd__(1) -> 3.5
1 + 2.5 -> 3.5 | tipi float

ifade             sonuç  istisna
'3' + 4               —  TypeError
3 + '4'               —  TypeError
3 + 2.5             5.5  —
True + 1              2  —
```

İlk satır belirleyici. Tam sayının `__add__` yöntemi bir gerçel sayı aldığında bir sonuç
değil, `NotImplemented` döndürüyor — "bu işi ben yapamam" anlamına gelen özel bir değer.
Bunun üzerine, dördüncü derste ölçülen düşüş işler: sağdaki işlenenin ters yöndeki yöntemi
denenir ve ikinci satırda görüldüğü gibi gerçel sayı işi üstlenir. Üçüncü satır sonucun
gerçel çıkmasının nedenini veriyor — hesabı yapan taraf gerçel sayı tipidir.

Yani "yükseltme" diye ayrı bir düzenek yoktur. Sayısal tipler birbirinin ters yöndeki
yöntemlerini karşıladıkları için birlikte çalışırlar; bu, dördüncü dersteki `__rmul__`
düşüşünün aynısıdır. Alt tablo sınırı da çiziyor: dizgi ile sayı hiçbir yönde birbirinin
yöntemini karşılamaz, dolayısıyla iki yazım da `TypeError` verir. Kimin solda kimin sağda
durduğu sonucu değiştirmiyor. Dizgi ile sayıyı toplamak isteyen kod, dönüşümü **kendisi**
yazmak zorundadır; dilin bu boşluğu kendiliğinden doldurmaması bir eksiklik değil, sessiz
sonuç üretmemek için verilmiş bir karardır.

Son satır bir Python ayrıntısını kapatıyor. `True + 1` ifadesi **2** veriyor, çünkü üçüncü
derste ölçüldüğü gibi doğruluk değerleri tam sayının bir alt tipidir. Burada bir dönüşüm
yapılmaz; nesne zaten bir tam sayıdır.

## Özet

- Dönüşüm yerleşikleri adı belli özel yöntemler çağırır: `int` `__int__`, `float`
  `__float__`, `str` `__str__`; yöntem yoksa dönüşüm `TypeError` ile düşer.
- `list(n)` ayrı bir yöntem istemez, yineleme protokolünü kullanır ve üç öğe için **5**
  çağrı öder.
- Dizin olarak kullanılmak `__int__` değil `__index__` ister; ilki çevrilebilirliği, ikincisi
  nesnenin zaten bir konum olduğunu bildirir.
- Yirmi dizgi denemesinin **11**'i istisnayla biter: tip çevrilemiyorsa **4** `TypeError`,
  tip doğru ama değer uygunsuzsa **7** `ValueError`.
- Başarısız dönüşüm özel bir dönüş değeri değil, bir istisna üretir; aksi hâlde o değer
  gerçek bir sonuçtan ayırt edilemezdi. Sessiz olan kusur, gerçel sayıya uğrayıp geri dönen
  büyük tam sayıdadır.
- Sayısal yükseltme ayrı bir kural değildir: tam sayının `__add__` yöntemi `NotImplemented`
  döndürür ve işi gerçel sayının ters yöndeki yöntemi üstlenir.

## Sonraki Adım

Bu ders bir konuyu kapatırken bir soruyu açık bıraktı. Dönüşüm başarısız olduğunda ortaya
bir **istisna** çıkıyor ve istisna, akışı bulunduğu yerden koparıp başka bir yere taşıyor —
yani bir kusur bildirimi değil, bir akış aracı. Sonraki konu akışın kendisini ele alacak ve
ilk dersi şu soruyla açacak: bir koşul yazıldığında sınanan şey nedir? `if` satırına bir
sayı, bir dizgi ya da boş bir liste konabilir; hepsi kabul edilir. Peki bir nesnenin **doğru
mu yanlış mı** sayıldığına kim karar veriyor — ve bu kararı veren yöntem yoksa ne oluyor?
