---
title: 'Veri Sınıfları'
source: 'https://academia.sh/tr/kurslar/python-nesne-ve-tipler/veri-siniflari'
course: 'Nesneye Dayalı Python ve Tipler'
language: tr
updated: '2026-08-17T18:10:29+00:00'
license: 'CC BY-SA 4.0'
---

# Veri Sınıfları

Dört kaynak satırlık kısa tanım elle yazılan on satırın yazdığı 4 özel yöntemin aynısını yazar; sıralama seçeneği 8'e, dondurma 6'ya, ikisi birlikte 10'a çıkarır ve dondurulan sınıfta beş işlemin 3'ü düşer.

Önceki iki ders yazılan gövdeleri saydı: on bir sözdizim için on iki gövde, tek bir alanın
denetimi için iki gövde daha. Oysa yazdığımız sınıfların çoğu aynı kalıbı tekrarlar. Birkaç
alan taşırlar, kurulumda o alanları doldururlar, alanlarıyla karşılaştırılırlar ve alanlarıyla
basılırlar. Bu kalıp her sınıfta elle yazıldığında hem uzar hem de her yazımda bir alanı
unutma olasılığı taşır.

Standart kitaplık bu kalıp için kısa bir tanım biçimi sunar. Bu dersin sorusu kolaylık değil,
ölçüdür: kısa tanım sınıfın sözlüğüne **hangi** özel yöntemleri gerçekten yazar, elle yazılmış
karşılığıyla yan yana konduğunda hangileri eksik kalır, ve tanıma eklenen her seçenek sözlüğe
kaç yeni ad koyar?

## Kısa Tanım Ne Yazıyor

Beş sınıf aynı iki alanı taşır: bir dizgi ve bir tam sayı. `ElleYazilan` kurulum, temsil ve
eşitlik gövdelerini elle yazar. Kalan dördü **veri sınıfı (data class)** tanımıdır: alanlar
adlarıyla ve açıklamalarıyla bildirilir, gövdeler bildirilmez. Dört tanım birbirinden yalnız
verilen seçeneklerle ayrılır — biri varsayılan, biri sıralama ister, biri dondurulmuştur, biri
ikisini birden.

Ölçüm on özel yöntem adını her sınıfın **kendi sözlüğünde** arar. Atalardan gelen adlar sayıya
girmez; sorulan şey kısa tanımın o sınıfa ne **yazdığıdır**.

- **SN62** — Beş sınıfın alanları aynıdır; adları, sıraları ve açıklamaları da aynıdır.
- **SN63** — "Kaynak satırı" satırı her tanımın kaç dolu kaynak satırı tuttuğunu sayar; boş
  satırlar sayılmaz, süsleyici satırı sayılır.
- **SN64** — Aranan on ad yalnız sınıfın kendi sözlüğünde aranır; `saglayan` kullanılmaz,
  çünkü ölçülen şey adın **yazılıp yazılmadığıdır**, nereden geldiği değil.
- **SN65** — "Karma değeri" satırı adın varlığına değil, **değerinin boş olup olmadığına**
  bakar; önceki dersin ölçtüğü boşaltma burada yeniden görünür.

```python
"""Kisa tanim sinifin sozlugune hangi ozel yontemleri yaziyor."""

import inspect
from dataclasses import dataclass


class ElleYazilan:
    def __init__(self, ad, sayi):
        self.ad = ad
        self.sayi = sayi

    def __repr__(self):
        return f"ElleYazilan(ad={self.ad!r}, sayi={self.sayi!r})"

    def __eq__(self, o):
        if not isinstance(o, ElleYazilan):
            return NotImplemented
        return (self.ad, self.sayi) == (o.ad, o.sayi)


@dataclass
class Varsayilan:
    ad: str
    sayi: int


@dataclass(order=True)
class Sirali:
    ad: str
    sayi: int


@dataclass(frozen=True)
class Donmus:
    ad: str
    sayi: int


@dataclass(frozen=True, order=True)
class DonmusSirali:
    ad: str
    sayi: int


SINIFLAR = (ElleYazilan, Varsayilan, Sirali, Donmus, DonmusSirali)
ARANAN = ("__init__", "__repr__", "__eq__", "__hash__", "__lt__", "__le__",
          "__gt__", "__ge__", "__setattr__", "__delattr__")


def satir(sinif):
    """Tanimin kac dolu kaynak satiri tuttugu."""
    return sum(1 for s in inspect.getsource(sinif).splitlines() if s.strip())


print(f"{'özel yöntem':<13s}" + "".join(f"{s.__name__:>13s}" for s in SINIFLAR))
for ad in ARANAN:
    print(f"{ad:<13s}"
          + "".join(f"{('yazılı' if ad in s.__dict__ else '.'):>13s}"
                    for s in SINIFLAR))

print(f"{'toplam yazılı':<13s}"
      + "".join(f"{sum(1 for a in ARANAN if a in s.__dict__):>13d}"
                for s in SINIFLAR))
print(f"{'kaynak satırı':<13s}" + "".join(f"{satir(s):>13d}" for s in SINIFLAR))
print(f"{'karma değeri':<13s}"
      + "".join(f"{('yok' if s.__hash__ is None else 'var'):>13s}"
                for s in SINIFLAR))
```

```
özel yöntem    ElleYazilan   Varsayilan       Sirali       Donmus DonmusSirali
__init__            yazılı       yazılı       yazılı       yazılı       yazılı
__repr__            yazılı       yazılı       yazılı       yazılı       yazılı
__eq__              yazılı       yazılı       yazılı       yazılı       yazılı
__hash__            yazılı       yazılı       yazılı       yazılı       yazılı
__lt__                   .            .       yazılı            .       yazılı
__le__                   .            .       yazılı            .       yazılı
__gt__                   .            .       yazılı            .       yazılı
__ge__                   .            .       yazılı            .       yazılı
__setattr__              .            .            .       yazılı       yazılı
__delattr__              .            .            .       yazılı       yazılı
toplam yazılı            4            4            8            6           10
kaynak satırı           10            4            4            4            4
karma değeri           yok          yok          yok          var          var
```

İlk iki sütun karşılaştırmanın kendisidir. Elle yazılan tanım **10** kaynak satırında **4** ad
yazıyor; kısa tanım **4** satırda aynı **4** adı yazıyor. Yazılan adlar birebir aynıdır —
kısa tanım eksik bir şey bırakmıyor, fazladan bir şey de eklemiyor. Ölçünün asıl söylediği
şudur: kısa tanımın kazandırdığı yalnız altı satır değildir. Elle yazılan sınıfta her alan adı
**üç gövdenin üçünde de** yazılır — kurulumda, temsilde ve eşitlikte. Yeni bir alan
eklendiğinde üç gövdenin üçü de güncellenmek zorundadır; kısa tanımda alan **bir kez**
bildirilir. Unutulan bir güncellemeyle sessizce eksik karşılaştıran bir eşitlik gövdesi, bu
kalıbın en pahalı hatasıdır ve hiçbir zaman istisna üretmez.

Dördüncü satır önceki dersin ölçtüğü düzeneği yeniden gösteriyor. Beş sınıfın beşinde de
`__hash__` adı sözlükte **yazılıdır**, ama alt satır ilk üçünde değerinin **boş** olduğunu
söylüyor. Eşitliği yazan her sınıf karma yeteneğini kaybeder; kısa tanım da bu kuralın dışında
değildir. Elle yazılan sınıf da aynı durumdadır ve aynı nedenle. Sonuç, veri sınıflarının en sık
şaşırtan yanıdır: değerle karşılaştırılabilen bir nesne, dondurulmadıkça bir kümeye ya da
sözlük anahtarına konamaz.

Seçenekler sözlüğe ne kattığını açıkça gösteriyor. Sıralama seçeneği **4** karşılaştırma
yöntemi ekler ve toplamı **8**'e çıkarır. Dondurma seçeneği yazma ve silme yollarını yakalayan
**2** yöntem ekler, toplamı **6** yapar ve karma değerini geri getirir. İkisi birlikte
verildiğinde toplam **10** olur — dört satırlık bir tanım, on gövdelik bir sınıf üretir.

Bu tablo kısa tanımın ne olduğunu da tanımlıyor: bir tanım değil, bir **yazma işlemidir.**
Sınıf gövdesindeki alan bildirimleri okunur ve karşılık gelen gövdeler sınıfın sözlüğüne
konur. Sözlüğe konan her ad, elle yazılabilecek olanın aynısıdır — bu yüzden kısa tanımla
yazılmış bir sınıfta herhangi bir yöntemi elle yazmak da onu **geçersiz kılar**, çünkü
gövdede zaten bulunan bir adın üzerine yazılmaz.

Yazılmayanları da saymak gerekir. Ölçüm on ad aradı ve dördüncü dersteki on bir sözdizimin
çoğu bu listede yok: uzunluk, yineleme, üyelik, sıra erişimi ve bağlam sözdizimleri kısa
tanımdan gelmez. Kısa tanım bir **kayıt** yazar, bir kap yazmaz. Bir veri sınıfının kap gibi
davranması isteniyorsa gerekli gövdeler yine elle yazılır.

Alanların nasıl bulunduğu da bir noktayı açıkta bırakıyor. Kısa tanım hangi adların alan
olduğunu, sınıf gövdesindeki **açıklamalardan** okur — `ad: str` yazımındaki tip adı alanın
varlığını bildirir. Bu tip adının çalışma zamanında ne yaptığı ayrı bir sorudur ve bu kursun
ikinci konusunda ölçülür; burada söylenebilecek olan, kısa tanımın onu yalnız bir **işaret**
olarak kullandığıdır.

## Değiştirilebilir Varsayılan

Kısa tanımın yalnız yazdıkları değil, **reddettikleri** de ölçülebilir. Python Temelleri kursu
varsayılan değerin işlev tanımlanırken **bir kez** değerlendirildiğini ve değiştirilebilir bir
varsayılanın çağrılar arasında paylaşıldığını ölçmüştü; **o ölçüm tekrarlanmaz.** Burada
sorulan şey aynı yazımın iki tanım biçiminde ne ürettiğidir.

- **SN66** — Üç tanım aynı alanı aynı varsayılanla kurmayı dener; ilki elle yazılan sınıf,
  ötekiler kısa tanımdır.
- **SN67** — Kurulamayan tanım ünlem önekiyle **istisnanın adını** kaydeder ve o satırın
  ölçüm sütunları boş bırakılır.
- **SN68** — Kurulan her tanımdan üç örnek var edilir ve her biri kaba kendi sırasını ekler;
  paylaşım `is` ile gösterilir.

```python
from dataclasses import field


class ElleKap:
    """Varsayilan deger bir kez degerlendirilir; uc ornek onu paylasir."""

    def __init__(self, ogeler=[]):
        self.ogeler = ogeler


def kisa_tanim(varsayilan):
    """Ayni varsayilani kisa tanimla kurmayi dener."""
    try:
        @dataclass
        class Gecici:
            ogeler: list = varsayilan
    except ValueError as e:
        return f"!{type(e).__name__}", None
    return "kuruldu", Gecici


TANIMLAR = (
    ("elle yazılan, varsayılan []", "kuruldu", ElleKap),
    ("kısa tanım, varsayılan []", *kisa_tanim([])),
    ("kısa tanım, üretici işlev", *kisa_tanim(field(default_factory=list))),
)

print(f"{'tanım':<28s} {'tanım anı':>16s} {'üç örneğin gördüğü':>20s} "
      f"{'kap paylaşılıyor':>17s}")
for ad, durum, sinif in TANIMLAR:
    if sinif is None:
        print(f"{ad:<28s} {durum:>16s} {'—':>20s} {'—':>17s}")
        continue
    ucu = [sinif() for _ in range(3)]
    for i, n in enumerate(ucu):
        n.ogeler.append(i)
    print(f"{ad:<28s} {durum:>16s} {str([len(n.ogeler) for n in ucu]):>20s} "
          f"{str(ucu[0].ogeler is ucu[2].ogeler):>17s}")
```

```
tanım                               tanım anı   üç örneğin gördüğü  kap paylaşılıyor
elle yazılan, varsayılan []           kuruldu            [3, 3, 3]              True
kısa tanım, varsayılan []         !ValueError                    —                 —
kısa tanım, üretici işlev             kuruldu            [1, 1, 1]             False
```

İlk satır bilinen sonucu veriyor: elle yazılan tanım **kuruluyor**, üç örnek tek kabı
paylaşıyor ve her biri **3** öğe görüyor. Hata çalışma zamanında da ortaya çıkmıyor; program
sessizce yanlış çalışıyor.

İkinci satır kısa tanımın farkıdır. Aynı yazım **tanım anında** `ValueError` ile düşüyor;
sınıf hiç kurulamıyor ve hatanın ortaya çıkacağı yer, hatanın yazıldığı satırın kendisi
oluyor. Üçüncü satır kabul edilen yazımı gösteriyor: varsayılan bir değer değil, her örnek
için çağrılacak bir **üretici işlev** verildiğinde tanım kuruluyor ve üç örnek **[1, 1, 1]**
görüyor — kap paylaşılmıyor.

Bu, ilk dersin sınıf gövdesindeki kap ölçümüyle aynı düzenektir ve üçüncü kez karşımıza
çıkıyor. Kısa tanımın buradaki katkısı yeni bir kural getirmek değil, var olan kuralı
**erkene almaktır**: bilinen bir yanlış yazımı çalışma zamanına bırakmak yerine tanım anında
reddeder.

Reddin ne kadar dar olduğunu da yazmak gerekir. Kısa tanım yalnız bildiği birkaç
değiştirilebilir tipi tanır; kendi yazdığımız değiştirilebilir bir sınıf varsayılan olarak
verildiğinde tanım kurulur ve paylaşım ilk satırdaki sonucun aynısını verir. Yakalanan şey
genel bir kural değil, sık yapılan bir yazımdır. Kuralın kendisi değişmemiştir: **varsayılan
değer tanım anında bir kez var edilir** ve örneğe ait olması gereken her kap bir üretici
işlevle bildirilir.

## Dondurmanın Ölçüsü

Son seçenek nesnenin yazılabilirliğini kapatır. Değişmezliğin gerekçesi ve değer nesnesi
kavramı Yazılım Tasarımı ve Mimari İlkeler müfredatında kuruldu; **o tartışma tekrarlanmaz.**
Burada ölçülen şey tek bir seçeneğin kaç işlemi kapattığı ve karşılığında ne açtığıdır.

- **SN69** — İki sınıf aynı iki alanı taşır; tek farkları dondurulmuş olup olmamalarıdır.
- **SN70** — Beş işlem denenir ve her biri **taze** bir örnek üzerinde çalışır; işlemler
  birbirini etkilemez.
- **SN71** — Son satır aynı değerleri taşıyan **iki ayrı** nesneyi karşılaştırır; kimlik `is`
  ile gösterilir ve **kimlik sayısı basılmaz.**

```python
from dataclasses import replace

ISLEMLER = (
    ("alana yazma", lambda n: setattr(n, "sayi", 9)),
    ("alan silme", lambda n: delattr(n, "sayi")),
    ("yeni alan açma", lambda n: setattr(n, "yeni", 1)),
    ("yerine yeni nesne", lambda n: replace(n, sayi=9)),
    ("kümeye koyma", lambda n: len({n})),
)


def dene(sinif, islev):
    try:
        islev(sinif("k", 1))
    except Exception as e:
        return f"!{type(e).__name__}"
    return "geçti"


print(f"{'işlem':<19s} {'Varsayilan':>21s} {'Donmus':>21s}")
for ad, islev in ISLEMLER:
    print(f"{ad:<19s} {dene(Varsayilan, islev):>21s} {dene(Donmus, islev):>21s}")

print()
for sinif in (Varsayilan, Donmus):
    dusen = sum(1 for _, f in ISLEMLER if dene(sinif, f).startswith("!"))
    print(f"{sinif.__name__}: beş işlemden düşen {dusen}, "
          f"geçen {len(ISLEMLER) - dusen}")

a, b = Donmus("k", 1), Donmus("k", 1)
print(f"ayrı iki nesne: a is b -> {a is b}, a == b -> {a == b}, "
      f"kümede kaç öğe -> {len({a, b})}")
```

```
işlem                          Varsayilan                Donmus
alana yazma                         geçti  !FrozenInstanceError
alan silme                          geçti  !FrozenInstanceError
yeni alan açma                      geçti  !FrozenInstanceError
yerine yeni nesne                   geçti                 geçti
kümeye koyma                   !TypeError                 geçti

Varsayilan: beş işlemden düşen 1, geçen 4
Donmus: beş işlemden düşen 3, geçen 2
ayrı iki nesne: a is b -> False, a == b -> True, kümede kaç öğe -> 1
```

Dondurma **3** işlemi kapatıyor ve **1** işlemi açıyor. Kapananların üçü de yazmadır: alana
yazma, alan silme ve yeni bir alan açma. Üçüncüsü ayrıca dikkat çekicidir — üçüncü dersteki
öznitelik kümesi bildirimiyle aynı kapıyı kapatır, ama farklı bir gerekçeyle. Açılan işlem
kümeye koymadır: dondurulmuş nesne karma değerine sahip olduğu için bir kapta anahtar
olabilir, sıradan veri sınıfı olamaz.

Dördüncü satır iki sınıfta da geçiyor ve dondurmanın nasıl kullanıldığını gösteriyor.
Değişmez bir nesne değiştirilmez, **yerine yenisi konur**; standart kitaplığın verdiği işlev
istenen alanları değiştirilmiş yeni bir nesne üretir. Yazma engellenmiştir, yeniden üretme
engellenmemiştir.

Son satır dondurulmuş bir veri sınıfının ne olduğunu tanımlıyor: `is` **False**, `==` **True**,
kümede **1** öğe. İki ayrı nesne, aynı değerleri taşıdıkları için birbirinin yerine geçer.
Kimlikle değil değerle tanımlanmak, bu üç sonucun toplamıdır — ve bu dersteki tanımın ürettiği
şey tam olarak budur.

Dondurmanın sınırını da yazmak gerekir, çünkü tablo onu göstermez. Kapatılan şey **alana
yazma** yoludur; alanın gösterdiği nesnenin kendisi değil. Dondurulmuş bir nesnenin alanı bir
liste tutuyorsa o listeye öğe eklemek hiçbir engelle karşılaşmaz — üçüncü dersteki ölçümün
son satırı burada aynen geçerlidir. Değişmezlik bir katman derinliğindedir; nesnenin gerçekten
değiştirilemez olması, alanlarının da değiştirilemez nesneler olmasına bağlıdır. Karma değeri
de aynı sınırı taşır: dondurulmuş bir sınıf alanında bir liste taşıyorsa kümeye koyma satırı
`TypeError` ile düşer, çünkü karma alanlardan üretilir.

## Özet

- Kısa tanım **4** kaynak satırında, elle yazılan **10** satırın yazdığı **4** özel yöntemin
  aynısını sınıfın sözlüğüne yazar; yazılan adlar birebir aynıdır.
- Eşitliği yazan her sınıfta olduğu gibi kısa tanımda da `__hash__` adı yazılır ve değeri
  **boş** bırakılır; karma yeteneği ancak dondurmayla geri gelir.
- Seçenekler sözlüğe ad ekler: sıralama **4** karşılaştırma yöntemi ekleyip toplamı **8**'e,
  dondurma **2** yöntem ekleyip **6**'ya çıkarır, ikisi birlikte **10** yapar.
- Değiştirilebilir varsayılan elle yazılan tanımda **kurulur** ve üç örnek tek kabı paylaşıp
  **[3, 3, 3]** görür; kısa tanımda **tanım anında** `ValueError` ile düşer ve üretici işlevle
  yazıldığında **[1, 1, 1]** görülür.
- Dondurma beş işlemin **3**'ünü kapatır ve **1**'ini açar: üç yazma yolu düşer, kümeye koyma
  geçer, yerine yeni nesne koyma iki sınıfta da geçer.
- Dondurulmuş iki ayrı nesne için `is` **False**, `==` **True** ve kümede **1** öğe kalır.

## Sonraki Adım

Bu ders bir sınıfın ne yazdığını sözlüğüne bakarak saydı; önceki dersler de yanıtı hep sınıf
ağacında aradı. İki yöntem de aynı varsayıma dayanıyor: bir nesnenin ne yapabildiğini bilmek
için onun **hangi sınıftan** geldiğini bilmek gerekir. Oysa dördüncü ders bunun aksini
göstermişti — katılım tipin adından değil, yazılan yöntemlerden geliyordu. `Sarmal` hiçbir
şeyden türemez ama dört yeteneğin dördünü de karşılar. Sonraki ders bu ikiliği sınamaya
çevirir: aynı nesne, **soy bağı arayan** bir sınamayla **yöntem arayan** bir sınamadan
hangisini geçer, soyut bir tabanın bildirdiği sözleşme hangi anda uygulanır, ve yöntem arayan
sınama gerçekten neye bakar?
