---
title: 'Sözdizim ve Girinti'
source: 'https://academia.sh/tr/kurslar/python-temelleri/sozdizim-ve-girinti'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:28+00:00'
license: 'CC BY-SA 4.0'
---

# Sözdizim ve Girinti

Girinti bir yazım tercihi değil dilbilgisinin parçasıdır: aynı 21 içerik birimi iki ayrı girintiyle iki ayrı ağaç ve iki ayrı sonuç üretir, dört ayrı genişlik tek bir ağaç verir ve on parçadan yalnız 5'i ifadedir.

Önceki ders kaynağın önce bütün olarak derlendiğini gösterdi ve derlemenin ilk adımının
metni **sözcük birimlerine** ayırmak olduğunu söyledi. O adımda bir soru açıkta kaldı:
satır başındaki boşluğa ne oluyor?

Ayraçla blok kuran dillerin çoğunda hiçbir şey — boşluk atılır, gövdenin nerede başlayıp
nerede bittiğini ayraçlar söyler ve girinti yalnızca okuyucu için konur. Python'da boşluk
atılmaz. **Girinti (indentation)** birim dizisine kendi birimlerini ekler ve blok yapısını
tam olarak o birimler kurar. Bunun gözlenebilir sonucu şudur: aynı sözcük birimi dizisi,
yalnız girintisi değiştirilerek başka bir ağaca ve başka bir sonuca dönüşür.

## Bloğu Ayraç Değil Boşluk Kurar

Birimlere ayırma adımı her satırın başındaki boşluğu ölçer ve bir yığıt üzerinde tutar. Bir
satır bir öncekinden daha içerideyse akışa bir `INDENT` birimi konur; daha dışarıdaysa,
kapanan her düzey için bir `DEDENT` birimi konur. Birden çok düzey aynı anda kapanıyorsa o
sayıda `DEDENT` üretilir, dolayısıyla dizideki `DEDENT` sayısı kapanan blok sayısını verir.
Bu birimlerin kaynak metinde karşılığı olan hiçbir karakter yoktur — boşluğun kendisinden
üretilirler.

Aşağıdaki iki kaynak, birimlerin adına bakıldığında ayırt edilemez. Yalnız bir satırın
girintisi farklıdır: `print` çağrısı birinde döngü gövdesinin dışında, ötekinde içindedir.

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

- **DT8** — İki kaynak yalnız son satırın girintisiyle ayrılır; hiçbir karakteri
  eklenmemiş, çıkarılmamış ya da değiştirilmiştir.
- **DT9** — Karşılaştırma birimlerin **adları** üzerinden yapılır; `INDENT`, `DEDENT`,
  `NEWLINE`, `NL` ve dosya sonu birimi "düzen birimi" sayılıp ayrı tutulur, kalanlar
  "içerik birimi" sayılır.
- **DT10** — Ağaç, çözümlenen yapının en üst düzeyindeki deyimlerin sınıf adlarıyla
  yazılır; döngü deyiminin gövdesi köşeli ayraç içinde verilir. Ağacın tam dökümü değil,
  bu ölçüme yeten kabuğu okunur.
- **DT11** — Yürütme çıktısı ayrı bir tampona alınır ve basılan satırların listesi olarak
  yazılır; ortama bağlı hiçbir değer okunmaz.

```python
"""Ayni sozcuk birimi dizisi, iki ayri girinti: uc gorunum."""
import ast
import contextlib
import io
import tokenize

DIS = "toplam = 0\nfor x in (1, 2, 3):\n    toplam += x\nprint(toplam)\n"
IC = "toplam = 0\nfor x in (1, 2, 3):\n    toplam += x\n    print(toplam)\n"
KAYNAK = {"gövde dışında": DIS, "gövde içinde": IC}
DUZEN = {"INDENT", "DEDENT", "NEWLINE", "NL", "ENDMARKER"}


def birimler(kaynak):
    ak = io.StringIO(kaynak).readline
    return [tokenize.tok_name[t.type] for t in tokenize.generate_tokens(ak)]


def agac(kaynak):
    parcalar = []
    for d in ast.parse(kaynak).body:
        ad = type(d).__name__
        if isinstance(d, ast.For):
            ad += "[" + ",".join(type(g).__name__ for g in d.body) + "]"
        parcalar.append(ad)
    return " ".join(parcalar)


def calistir(kaynak):
    tampon = io.StringIO()
    with contextlib.redirect_stdout(tampon):
        exec(compile(kaynak, "<ders>", "exec"), {})
    return tampon.getvalue().split()


for ad, kaynak in KAYNAK.items():
    tumu = birimler(kaynak)
    icerik = [b for b in tumu if b not in DUZEN]
    print(f"{ad:14s} birim {len(tumu)}  düzen dışı {len(icerik)}  "
          f"INDENT/DEDENT {[i for i, b in enumerate(tumu) if b in ('INDENT', 'DEDENT')]}")

a, b = (birimler(k) for k in KAYNAK.values())
print(f"düzen birimleri atılınca iki dizi eşit mi: "
      f"{[x for x in a if x not in DUZEN] == [x for x in b if x not in DUZEN]}")
print()
for ad, kaynak in KAYNAK.items():
    print(f"{ad:14s} ağaç: {agac(kaynak)}")
    print(f"{'':14s} basılan: {calistir(kaynak)}")
```

```
gövde dışında  birim 28  düzen dışı 21  INDENT/DEDENT [16, 21]
gövde içinde   birim 28  düzen dışı 21  INDENT/DEDENT [16, 26]
düzen birimleri atılınca iki dizi eşit mi: True

gövde dışında  ağaç: Assign For[AugAssign] Expr
               basılan: ['6']
gövde içinde   ağaç: Assign For[AugAssign,Expr]
               basılan: ['1', '3', '6']
```

İki kaynak da **28** birim üretiyor ve bunların **21**'i içerik birimi. Düzen birimleri
atıldığında kalan iki dizi **birebir eşit** — adları da sıraları da aynı. Ayrım tek bir
birimin yerindedir: `DEDENT` birinde **21.**, ötekinde **26.** sırada duruyor. Kaynakta
değişen tek şey dört boşluktur ve o dört boşluk bir birimi beş sıra öteye taşımıştır.

Bu tek fark ağacı değiştiriyor. Birinci kaynakta çağrı, döngünün **kardeşi**: ağaçta
`For[AugAssign]` bittikten sonra ayrı bir `Expr` geliyor. İkincisinde çağrı döngünün
**çocuğu**: `For[AugAssign,Expr]`. Sonuç da buna göre ayrışıyor — biri tek satır, öteki üç
satır basıyor.

Buradan çıkan kural, dile giriş için en pahalı yanlış anlamalardan birini kapatır:
**girintiyi bozmak bir üslup kusuru değil, programı değiştirmektir.** Ayraçlı bir dilde
aynı iki kaynak birbirinin biçimlendirilmiş hâli olurdu ve ikisi de aynı şeyi yapardı.
Burada girinti tek belirleyicidir; başka hiçbir işaret gövdenin sınırını söylemez.

## Genişlik Serbest, Tutarlılık Zorunlu

Girintinin dilbilgisel olması, belli bir **genişliğin** dilbilgisel olduğu anlamına gelmez.
Dil bir sayı dayatmaz; dayattığı şey bir bloğun kendi içinde tutarlı olmasıdır. Sınır
gözlenebilir: aynı yapı dört ayrı genişlikle yazılıp ağaçları karşılaştırılabilir, sonra
tutarsız dört kaynak derlenmeye çalışılabilir.

- **DT12** — Doğru kaynaklarda genişlik değişir ama blok içinde tutarlı kalır; bozuk
  kaynaklarda tutarlılık dört ayrı biçimde kırılır. Kaynaklar derlenir, **yürütülmez** —
  ölçülen şey derleme aşamasının kabul edip etmediğidir.

```python
"""Girintinin kurali: genislik serbest, tutarlilik zorunlu."""
import ast

GENISLIK = {"iki boşluk": "if 1:\n  a = 1\n  b = 2\n",
            "dört boşluk": "if 1:\n    a = 1\n    b = 2\n",
            "sekiz boşluk": "if 1:\n        a = 1\n        b = 2\n",
            "sekme": "if 1:\n\ta = 1\n\tb = 2\n"}

BOZUK = {"girinti hiç yok": "for x in (1, 2):\nb = 1\n",
         "beklenmeyen girinti": "a = 0\n    b = 1\n",
         "hizalanmayan çıkış": "if 1:\n        a = 1\n    b = 2\n",
         "sekme ile boşluk karışık": "if 1:\n\ta = 1\n        b = 2\n"}


def agac(kaynak):
    d = ast.parse(kaynak).body[0]
    return f"{type(d).__name__}[{','.join(type(g).__name__ for g in d.body)}]"


print("aynı yapı, ayrı genişlik:")
for ad, kaynak in GENISLIK.items():
    print(f"  {ad:12s} ağaç: {agac(kaynak)}")
print(f"  dört ağacın hepsi aynı mı: "
      f"{len({agac(k) for k in GENISLIK.values()}) == 1}")

print("\ntutarsız girinti:")
for ad, kaynak in BOZUK.items():
    try:
        compile(kaynak, "<ders>", "exec")
        print(f"  {ad:24s} derlendi")
    except SyntaxError as e:
        print(f"  {ad:24s} {type(e).__name__}")
print(f"  IndentationError bir SyntaxError mı: "
      f"{issubclass(IndentationError, SyntaxError)}")
print(f"  TabError bir IndentationError mı: "
      f"{issubclass(TabError, IndentationError)}")
```

```
aynı yapı, ayrı genişlik:
  iki boşluk   ağaç: If[Assign,Assign]
  dört boşluk  ağaç: If[Assign,Assign]
  sekiz boşluk ağaç: If[Assign,Assign]
  sekme        ağaç: If[Assign,Assign]
  dört ağacın hepsi aynı mı: True

tutarsız girinti:
  girinti hiç yok          IndentationError
  beklenmeyen girinti      IndentationError
  hizalanmayan çıkış       IndentationError
  sekme ile boşluk karışık TabError
  IndentationError bir SyntaxError mı: True
  TabError bir IndentationError mı: True
```

Dört genişlik tek bir ağaç veriyor. Dilbilgisel olan şey girintinin **miktarı** değil,
**yapısı**: bir düzeyin açılıp aynı hizada sürmesi ve kapanırken daha önce açılmış bir
hizaya oturması. İki boşlukla yazılmış program ile sekiz boşlukla yazılmış program aynı
programdır; aralarındaki seçim ekip sözleşmesine kalır, dile değil.

Tutarlılık kırıldığında dördünde de derleme durur. Üçü `IndentationError` verir: gövdesi
hiç açılmayan bir blok, hiçbir şeyi açmadan içeri kayan bir satır ve daha önce açılmış
hiçbir hizaya oturmayan bir çıkış. Dördüncüsü ayrılır — sekme ile boşluğun karıştığı
kaynak `TabError` verir, çünkü bu iki karakterin genişliği kaynağa bakarak çözülemez.
Çıktının son iki satırı üçünün de tek bir soydan geldiğini gösteriyor: `TabError` bir
`IndentationError`, o da bir `SyntaxError`.

Bu soy zinciri önceki dersin sınırını da yerine oturtuyor. Girinti kusurları **derleme
aşamasında** bulunur; hiçbiri yürütmeye kalmaz. Dosyanın son satırındaki bozuk bir girinti,
ilk satırdaki atamanın da yapılmamasına yol açar.

## Mantıksal Satır ile Fiziksel Satır

Girintinin dilbilgisel olması bir yerde biter ve sınırı bilmek gerekir. Blok yapısını kuran
şey **mantıksal satırın** başındaki boşluktur; ekrandaki her satır başı bir mantıksal satır
başlatmaz. Bir ifade açılmış bir ayracın içindeyken satır sonu deyimi bitirmez, akışa
`NEWLINE` yerine `NL` konur ve **o satırların girintisi hiçbir birim üretmez**. Aynı
süreklilik ters bölü ile de kurulabilir.

- **DT13** — Dört biçim aynı toplamı yazar ve yalnız satırlara bölünüşleriyle ayrılır;
  ölçülen şey fiziksel satır sayısı, mantıksal satır sonu (`NEWLINE`), süreklilik satır
  sonu (`NL`) ve `INDENT` sayısıdır. Değer sütunu kaynağın kendi ürettiği toplamdır.

```python
"""Mantiksal satir ile fiziksel satir: ayrac icinde girinti dilbilgisel degildir."""
import ast
import io
import tokenize

BICIM = {
    "tek satır": "toplam = 1 + 2 + 3\n",
    "ayraç içinde hizalı": "toplam = (1 +\n          2 +\n          3)\n",
    "ayraç içinde savruk": "toplam = (1 +\n2 +\n              3)\n",
    "ters bölü ile": "toplam = 1 + \\\n    2 + \\\n    3\n",
}


def say(kaynak):
    ak = io.StringIO(kaynak).readline
    adlar = [tokenize.tok_name[t.type] for t in tokenize.generate_tokens(ak)]
    return adlar.count("NEWLINE"), adlar.count("NL"), adlar.count("INDENT")


print(f"{'biçim':<21s} {'fiziksel':>8s} {'NEWLINE':>7s} {'NL':>3s} {'INDENT':>6s}"
      f"  ağaç     değer")
for ad, kaynak in BICIM.items():
    mantiksal, nl, ind = say(kaynak)
    ortam = {}
    exec(compile(kaynak, "<ders>", "exec"), ortam)
    agac = " ".join(type(d).__name__ for d in ast.parse(kaynak).body)
    print(f"{ad:<21s} {len(kaynak.splitlines()):8d} {mantiksal:7d} {nl:3d} {ind:6d}"
          f"  {agac:8s} {ortam['toplam']}")
```

```
biçim                 fiziksel NEWLINE  NL INDENT  ağaç     değer
tek satır                    1       1   0      0  Assign   6
ayraç içinde hizalı          3       1   2      0  Assign   6
ayraç içinde savruk          3       1   2      0  Assign   6
ters bölü ile                3       1   0      0  Assign   6
```

Dört biçim de tek bir `Assign` düğümü ve tek bir değer veriyor. Üçü **3** fiziksel satıra
yayıldığı hâlde hepsinde `NEWLINE` sayısı **1**: mantıksal satır bir tanedir. Ayraçlı iki
biçimde aradaki satır sonları `NL` olarak, yani "burada bir deyim bitmedi" işaretiyle
geçiyor. Ters bölülü biçimde satır sonu birime hiç dönüşmüyor; süreklilik daha metin
birimlere ayrılmadan çözülüyor.

En çok söyleyen sütun `INDENT`: dördünde de **0**. "Savruk" biçimin ikinci satırı sütun
başından, üçüncüsü çok içeriden başlıyor ve hiçbiri bir şey değiştirmiyor. Demek ki girinti
dilbilgisel olmayı **ayracın içinde bırakır**; orada yapılan hizalama tümüyle okuyucu
içindir ve tutarsızlığı bir kusur üretmez. Kural şöyle daraltılabilir: girinti yalnız bir
mantıksal satırın başında anlam taşır.

## Deyim ve İfade

Girinti bir blok kurar; blok ise **deyimlerden** oluşur. Bu, dilin ikinci temel ayrımını
gerektirir. **İfade (expression)** bir değer üretir: hesaplanır ve geriye bir nesne bırakır.
**Deyim (statement)** bir iş yapar: bir ad bağlar, bir bloğa girer, akışı yönlendirir; geriye
bir değer bırakmaz.

Ayrım sezgiye bırakılmak zorunda değildir, çünkü derleme kipi onu doğrudan söyler. `eval`
kipi yalnız bir ifade kabul eder; `exec` kipi bir deyim dizisi kabul eder.

- **DT14** — Her parça iki kipte de derlenmeye çalışılır; ölçülen şey kabul edilip
  edilmediğidir. Değeri yazılan parçalar tek bir adın bağlı olduğu bir ortamda
  değerlendirilir, dolayısıyla değer sütunu ortama değil o bağlamaya bağlıdır.

```python
"""Deyim mi ifade mi: 'eval' kipi yalniz ifadeyi derler, 'exec' kipi ikisini de."""

PARCALAR = (
    "2 + 3",
    "toplam",
    "len('olcum')",
    "[k for k in (1, 2, 3)]",
    "toplam if toplam else 0",
    "toplam = 5",
    "toplam += 1",
    "if toplam: pass",
    "for k in (1, 2): pass",
    "pass",
)

print(f"{'parça':<26s} {'ifade':>5s} {'deyim':>5s}  değeri")
ifade_sayisi = deyim_sayisi = 0
for p in PARCALAR:
    try:
        kod = compile(p, "<ders>", "eval")
        ifade = True
    except SyntaxError:
        ifade = False
    try:
        compile(p, "<ders>", "exec")
        deyim = True
    except SyntaxError:
        deyim = False
    ifade_sayisi += ifade
    deyim_sayisi += deyim
    deger = repr(eval(kod, {"toplam": 3})) if ifade else "—"
    print(f"{p:<26s} {str(ifade):>5s} {str(deyim):>5s}  {deger}")

print(f"\n{len(PARCALAR)} parçadan ifade {ifade_sayisi}, deyim {deyim_sayisi}; "
      f"yalnız deyim olan {deyim_sayisi - ifade_sayisi}")
```

```
parça                      ifade deyim  değeri
2 + 3                       True  True  5
toplam                      True  True  3
len('olcum')                True  True  5
[k for k in (1, 2, 3)]      True  True  [1, 2, 3]
toplam if toplam else 0     True  True  3
toplam = 5                 False  True  —
toplam += 1                False  True  —
if toplam: pass            False  True  —
for k in (1, 2): pass      False  True  —
pass                       False  True  —

10 parçadan ifade 5, deyim 10; yalnız deyim olan 5
```

On parçanın **5**'i ifade, **10**'u deyim. Deyim sütununun tamamen dolu olması ayrımın
yönünü verir: **her ifade aynı zamanda bir deyimdir** — tek başına bir satıra konduğunda
değeri hesaplanır ve atılır. Tersi geçerli değildir; yalnız deyim olan **5** parça bir
ifadenin durabileceği hiçbir yere konamaz.

Ayrımın kurs için doğrudan bir sonucu var. Önceki dersin ölçtüğü on bir biçimin hepsi bir
nesneyi **tüketiyordu** ve tükettikleri şey bir ifadenin değeriydi; özel yöntemler ifadeler
üzerinde çalışır. Tabloda `toplam += 1` satırının ifade çıkmaması da bu yüzden önemlidir:
Programlama Temelleri kursu bileşik atamanın bir deyim olduğunu söylemişti, burada ölçülen
şey o deyimin **hangi yöntemi çağırdığı** ve dönen değeri ne yaptığıdır. `__iadd__`
çağrısının sonucu ortada bir değer olarak durmaz, doğrudan ada geri bağlanır — ayrıntısı
işleçler dersinde ödenecek.

Son bir gözlem tabloda saklıdır: `if toplam: pass` tek satırda yazıldığı hâlde geçerli bir
deyimdir ve hiç girinti kullanmaz. Girinti bir bloğu yazmanın **tek** yolu değildir; bloğu
zorunlu kılan şey deyimin kendisidir, girinti ise birden çok deyimli bir gövdeyi yazmanın
yoludur.

## Özet

- Girinti atılmaz; satır başındaki boşluk `INDENT` ve `DEDENT` birimlerine çevrilir ve blok
  yapısını bu birimler kurar.
- Yalnız girintisiyle ayrılan iki kaynak aynı **21** içerik birimini aynı sırada taşır;
  tek bir `DEDENT` biriminin yeri ağacı ve sonucu değiştirir.
- Girintinin genişliği serbesttir — dört ayrı genişlik tek bir ağaç verir — ama bir blok
  içinde tutarlı olmak zorundadır.
- Tutarsız girinti derleme aşamasında durdurur; `TabError` bir `IndentationError`, o da bir
  `SyntaxError`'dır.
- Girinti yalnız mantıksal satır başında dilbilgiseldir: açık ayracın içindeki **3** fiziksel
  satır tek bir `NEWLINE` üretir ve `INDENT` sayısı **0** kalır.
- On parçadan **5**'i ifade, **10**'u deyimdir: her ifade bir deyim olarak yazılabilir,
  hiçbir deyim ifadenin yerine konamaz.

## Sonraki Adım

Bu derste en sık yazılan deyim olan atama, tabloda yalnızca "ifade değil" olduğu için
göründü; ne yaptığına bakılmadı. Programlama Temelleri kursu atamanın bir bağlama olduğunu
kurmuştu — ad bir kutu değil, bir nesneye takılan etikettir. Sonraki ders bu bağı nesne
tarafından ölçer: iki ad aynı nesneye bağlı olduğunda bunu ne söyler, eşit iki değerin aynı
nesne çıkması hangi koşulda gerçekleşir ve bir tipin "değiştirilemez" olması bağlamayı nasıl
etkiler?
