---
title: 'Kapsam Kuralları'
source: 'https://academia.sh/tr/kurslar/python-temelleri/kapsam-kurallari'
course: 'Python Temelleri'
language: tr
updated: '2026-08-17T18:10:29+00:00'
license: 'CC BY-SA 4.0'
---

# Kapsam Kuralları

Ad araması dört düzeyde yürür ve hangi düzeyde durduğunu adın okunduğu yer değil, atandığı yer belirler: gövdeye tek bir atama satırı eklemek aynı okumayı geçerli bir değerden UnboundLocalError'a çevirir.

Önceki ders argümanların parametrelere nasıl bağlandığını ölçtü. Bağlanan her argüman
gövdede bir **ad** kurar; ama gövde yalnız o adları kullanmaz. Kendi kurduğu adlar,
çevreleyen tanımdan gelenler, dosyanın en dışında duranlar ve dilin kendi sağladıkları da
oradadır — ve hepsi aynı yazımla, çıplak bir adla okunur.

Programlama Temelleri kursunun kapsam dersi bu arama sırasını dilden bağımsız bir **kavram**
olarak kurdu: yerelden başlanır, çevreleyene ve küresele gidilir, yerleşiklerle biter, ilk
bulunan kazanır. O ders kapsamı görünürlükle, yaşam süresini ömürle tanımladı ve
gölgelemenin ne olduğunu anlattı. Burada aynı sıra bir **arama zinciri** olarak ölçülür ve
ölçüm bir soruya odaklanır: bir adın hangi düzeyde aranacağını belirleyen şey nedir?
Yanıt sezgiye aykırıdır — belirleyen şey adın **okunduğu** yer değil, gövdede bir yerde
**atanıp atanmadığıdır**.

## Dört Düzey

Python'da ad araması dört düzeyde yürür ve sırası sabittir:

1. **Yerel** — içinde bulunulan fonksiyon gövdesi.
2. **Kapsayan** — onu çevreleyen fonksiyon gövdeleri, içten dışa.
3. **Genel** — dosyanın en dış düzeyi.
4. **Yerleşik** — dilin kendi sağladığı adlar.

Arama ilk bulduğu yerde durur ve alttaki düzeylere hiç bakmaz. Dördü de bulamazsa sonuç
bir değer değil, `NameError` olur.

Dördüncü düzey öbürlerinden farklıdır: içindeki adları program yazmaz, dil koyar. Ama
arama sırasındaki yeri özel değildir — en sonda olduğu için, üstteki üç düzeyden herhangi
biri aynı adı tanımlarsa yerleşik olan **gölgelenir** ve o gövdede erişilemez olur.

## Adı Yerel Yapan Şey

Asıl kural buradadır ve gövdenin tamamını ilgilendirir. Python bir gövdedeki adın hangi
düzeye ait olduğuna **çalışma sırasında değil, gövdeyi okurken** karar verir. Kural tek
cümledir: **gövdede bir yerde ada atama yapılıyorsa, o ad o gövdenin tamamı için
yereldir.**

"Bir yerde" ifadesi harfiyen alınmalıdır. Atama gövdenin en son satırında olsa bile ad
gövdenin en başından itibaren yereldir. Bu yüzden atamadan **önce** yapılan bir okuma,
dıştaki değeri bulmaz — henüz değer almamış yerel adı bulur ve sonuç bir istisna olur:
`UnboundLocalError`.

Bu, gölgelemenin ölçülebilir hâlidir. Programlama Temelleri kursu gölgelemeyi "dıştaki ad
erişilemez hâle gelir" diye tanımlamıştı; buradaki ölçüm erişilemezliğin **nereden
başladığını** söylüyor — atama satırından değil, gövdenin ilk satırından.

## Dışarı Yazmak

Kuralın doğrudan sonucu şudur: dıştaki bir ada **atama yapmak** çıplak yazımla olanaksızdır.
Atama her zaman yerel bir ad kurar; dıştakini değiştirmez, onu gölgeler.

Dil bu yüzden iki bildirim tanır. `global`, adın genel düzeye ait olduğunu bildirir ve o
gövdedeki atamaları oraya yönlendirir. `nonlocal`, adın **kapsayan** bir gövdeye ait
olduğunu bildirir ve atamaları oraya yönlendirir; genel düzeye bakmaz, bulamazsa hata
verir.

Okumak için bildirim gerekmez. Bildirim yalnız **yazma** yönünü değiştirir; kural yazma
kuralıdır, okuma kuralı değil. Bu asimetri kasıtlıdır: dıştaki bir değeri okumak o değeri
kimse için değiştirmez, ama ona yazmak gövdenin dışında görülebilir bir sonuç bırakır.
Bildirim zorunluluğu, o sonucun kazara doğmasını engeller — dışarı yazan her gövde bunu
tek satırla ilan etmek zorundadır.

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

- **PA24** — Kâhin, her düzeyin o düzeyi adlandıran ayrı bir dizgi bağlamasıdır; dönen
  değer, aramanın hangi düzeyde durduğunu doğrudan söyler.
- **PA25** — Aynı ad `SINIR` dört durumda ölçülür ve durumlar yalnız **hangi düzeylerin
  o adı tanımladığı** bakımından ayrılır; gövdelerin okuma satırı birebir aynıdır.
- **PA26** — Yerleşik düzey ayrı bir adla ölçülür, çünkü o düzeydeki adları program
  yazamaz. Ölçüm için dilin sağladığı `min` adı kullanılır ve üstteki düzeylerde
  gölgelenir.
- **PA27** — Atama kuralı üç gövdeyle ölçülür: yalnız okuyan, okuyup sonra atayan, yalnız
  atayan. Üçünde de okuma satırı aynıdır; değişen tek şey gövdede bir atamanın **bulunup
  bulunmadığı** ve yeridir.
- **PA28** — Yazma yönü üç durumda ölçülür: bildirimsiz, `nonlocal` bildirimiyle ve
  `global` bildirimiyle. Genel düzeydeki ad ölçümün sonunda değiştiği için o satır en
  sonda çalıştırılır.
- **PA29** — İstisnalar yalnız **sınıf adıyla** yazılır, iletileri yazılmaz.
- **PA30** — Kapanış ölçümünde üç işlev bir döngüde üretilir ve **döngü bittikten sonra**
  çağrılır. Çağrının döngüden sonraya bırakılması kasıtlıdır; ölçülen şey adın **ne zaman
  çözüldüğüdür**, hangi değeri taşıdığı değil.

## Ölçüm

```python
"""Dort kapsam duzeyi: ad hangi duzeyde bulunur, atama onu nereye tasir."""

SINIR = "genel"


def olc(islev):
    try:
        return islev()
    except Exception as e:
        return f"!{type(e).__name__}"


def hicbiri():
    return TANIMSIZ_AD


def yalniz_genel():
    return SINIR


def kapsayan_da_var():
    SINIR = "kapsayan"

    def ic():
        return SINIR
    return ic()


def yerel_de_var():
    SINIR = "kapsayan"

    def ic():
        SINIR = "yerel"
        return SINIR
    return ic()


ARAMA = (
    ("hiçbir düzeyde yok", hicbiri, "-"),
    ("yalnız genel", yalniz_genel, "genel"),
    ("genel + kapsayan", kapsayan_da_var, "genel, kapsayan"),
    ("genel + kapsayan + yerel", yerel_de_var, "genel, kapsayan, yerel"),
)

print(f"{'adın tanımlı olduğu düzeyler':<26s} {'bulunan':<22s} sonuç")
for ad, f, tanimli in ARAMA:
    print(f"  {ad:<24s} {tanimli:<22s} {olc(f)}")


def yerlesigi_kullanir():
    return min([3, 1, 2])


def yerlesigi_kapsayan_golgeler():
    min = "kapsayan gölgeledi"

    def ic():
        return min
    return ic()


def yerlesigi_yerel_golgeler():
    def ic():
        min = "yerel gölgeledi"
        return min
    return ic()


print()
print(f"{'yerleşik ad min':<30s} sonuç")
for ad, f in (("hiçbir düzey tanımlamaz", yerlesigi_kullanir),
              ("kapsayan düzey tanımlar", yerlesigi_kapsayan_golgeler),
              ("yerel düzey tanımlar", yerlesigi_yerel_golgeler)):
    print(f"  {ad:<28s} {olc(f)}")


def yalniz_okur():
    return SINIR


def okur_sonra_atar():
    once = SINIR
    SINIR = "yerel"
    return once


def yalniz_atar():
    SINIR = "yerel"
    return SINIR


print()
print(f"{'gövdede SINIR ile yapılan':<30s} {'gövdedeki okuma':<18s} sonuç")
for ad, f, okuma in (("yalnız okunur", yalniz_okur, "atamadan önce yok"),
                     ("okunur, sonra atanır", okur_sonra_atar, "atamadan önce"),
                     ("yalnız atanır", yalniz_atar, "atamadan sonra")):
    print(f"  {ad:<28s} {okuma:<18s} {olc(f)}")


def genel_bildirir():
    global SINIR
    SINIR = "içeriden yazıldı"


def kapsayan_bildirir():
    SINIR = "kapsayan"

    def ic():
        nonlocal SINIR
        SINIR = "içeriden yazıldı"
    ic()
    return SINIR


def bildirimsiz_yazar():
    SINIR = "kapsayan"

    def ic():
        SINIR = "içeriden yazıldı"
    ic()
    return SINIR


print()
print(f"{'gövdeden dışarı yazma':<26s} {'hedef düzey':<12s} dıştaki adın sonraki değeri")
for ad, f, hedef in (("bildirim yok", bildirimsiz_yazar, "kapsayan"),
                     ("nonlocal bildirimi", kapsayan_bildirir, "kapsayan")):
    print(f"  {ad:<24s} {hedef:<12s} {olc(f)}")

once = SINIR
genel_bildirir()
print(f"  {'global bildirimi':<24s} {'genel':<12s} {once} -> {SINIR}")


def gec_baglanan():
    islevler = []
    for i in range(3):
        def uret():
            return i
        islevler.append(uret)
    return [f() for f in islevler]


def varsayilanla_yakalanan():
    islevler = []
    for i in range(3):
        def uret(i=i):
            return i
        islevler.append(uret)
    return [f() for f in islevler]


def dongu_sonrasi_ad():
    for i in range(3):
        pass
    return i


print()
print(f"{'döngüde üretilen üç işlev':<30s} çağrıldıklarında dönen")
print(f"  {'gövdede çıplak ad':<28s} {gec_baglanan()}")
print(f"  {'varsayılanla yakalanmış ad':<28s} {varsayilanla_yakalanan()}")
print(f"  {'döngü bittikten sonra ad':<28s} {dongu_sonrasi_ad()}")
```

```
adın tanımlı olduğu düzeyler bulunan                sonuç
  hiçbir düzeyde yok       -                      !NameError
  yalnız genel             genel                  genel
  genel + kapsayan         genel, kapsayan        kapsayan
  genel + kapsayan + yerel genel, kapsayan, yerel yerel

yerleşik ad min                sonuç
  hiçbir düzey tanımlamaz      1
  kapsayan düzey tanımlar      kapsayan gölgeledi
  yerel düzey tanımlar         yerel gölgeledi

gövdede SINIR ile yapılan      gövdedeki okuma    sonuç
  yalnız okunur                atamadan önce yok  genel
  okunur, sonra atanır         atamadan önce      !UnboundLocalError
  yalnız atanır                atamadan sonra     yerel

gövdeden dışarı yazma      hedef düzey  dıştaki adın sonraki değeri
  bildirim yok             kapsayan     kapsayan
  nonlocal bildirimi       kapsayan     içeriden yazıldı
  global bildirimi         genel        genel -> içeriden yazıldı

döngüde üretilen üç işlev      çağrıldıklarında dönen
  gövdede çıplak ad            [2, 2, 2]
  varsayılanla yakalanmış ad   [0, 1, 2]
  döngü bittikten sonra ad     2
```

## Zincirin Dört Basamağı

Üst tablo arama zincirini basamak basamak kuruyor. Dört satırın **okuma satırı birebir
aynı**; değişen tek şey hangi düzeylerin o adı tanımladığı.

Hiçbir düzeyde tanımlı olmadığında sonuç `NameError`. İkinci satırda ad yalnız genel
düzeyde var ve bulunan o. Üçüncü satırda kapsayan düzey de aynı adı tanımlıyor ve
**kapsayan kazanıyor** — genel düzeydeki ad hâlâ orada duruyor ama aramaya hiç
gelmiyor. Dördüncüde yerel düzey de ekleniyor ve bu kez **yerel kazanıyor**.

Örüntü şudur: her yeni düzey, kendinden **dıştaki** her şeyi kapatıyor. Arama dıştan içe
değil, **içten dışa** yürüyor ve ilk bulduğunda duruyor. Üç düzey aynı adı tanımladığında
üçü yarışmıyor; en içteki öbür ikisini sınamaya bile sokmuyor.

Orta tablo dördüncü düzeyi ekliyor. İlk satırda hiçbir düzey `min` adını tanımlamıyor ve
arama yerleşik düzeye kadar inip dilin sağladığı adı buluyor; sonuç, üç öğelik listenin
en küçüğü olan **1**. Sonraki iki satırda aynı ad önce kapsayan, sonra yerel düzeyde
tanımlanıyor ve ikisinde de yerleşik olan gölgeleniyor. Yerleşik düzeyin arama sırasında
ayrıcalığı yok; en sonda olduğu için **her zaman en kolay gölgelenen** düzey.

Bunun pratik sonucu, bir yerleşiğin adını yerel bir değişkene vermenin o gövdede o
yerleşiği kullanılamaz kılmasıdır. Hata çıkmaz, uyarı çıkmaz; ad artık başka bir şeyi
gösterir.

## Tek Bir Atama Satırı

Üçüncü tablo dersin ana ölçümüdür ve üç satırın **okuma satırı yine aynıdır**.

Birinci satır: gövde `SINIR` adını yalnız okuyor, hiçbir yerde atamıyor. Arama zinciri
yürüyor, genel düzeyde bulunuyor, sonuç **genel**.

İkinci satır: gövde önce aynı okumayı yapıyor, **sonra** ada bir atama yapıyor. Okuma
satırı atamadan öncedir ve birinci satırdakiyle karakter karakter aynıdır. Ama sonuç
artık bir değer değil, **`UnboundLocalError`**.

Aradaki tek fark, gövdenin **ilerideki** bir satırında bir atamanın bulunmasıdır. O atama
adı gövdenin tamamı için yerel yapıyor; okuma satırına gelindiğinde arama artık genel
düzeye hiç çıkmıyor, yerel düzeyde duruyor ve orada henüz değer almamış bir ad buluyor.
Zincir kırılmıyor — **hiç kurulmuyor**.

Buradaki sıra ilişkisi kritiktir: adın yerel olmasına karar veren şey çalışma sırası
değil, gövdenin **tümüne bakılarak** verilen bir karardır. Bu yüzden hatayı üreten satır,
hatanın nedenini içermez; neden aşağıdaki atama satırıdır. Üçüncü satır bunu tamamlıyor —
gövde yalnız atayıp sonra okuduğunda sorun yok, sonuç **yerel**.

## Yazmanın Üç Yolu

Alt tablo yazma yönünü ölçüyor. Birinci satırda iç gövde bildirimsiz bir atama yapıyor ve
dıştaki ad **değişmiyor**: sonuç hâlâ `kapsayan`. Atama dıştakini güncellemedi, iç gövdeye
ait yeni bir ad kurdu ve o ad gövde bitince ortadan kalktı. Yazılan satır bir güncelleme
gibi görünüyor; yaptığı iş bir gölgeleme.

İkinci satırda aynı gövde `nonlocal` bildirimiyle yazıyor ve dıştaki ad **değişiyor**.
Üçüncü satırda `global` bildirimi genel düzeydeki adı değiştiriyor; ölçümden önce `genel`
olan değer sonrasında `içeriden yazıldı` oluyor.

Üç satırın söylediği şudur: gövdeden dışarı yazmak **bildirimle** olur, çıplak atamayla
olmaz. Bildirim yeni bir yetenek eklemiyor; yalnız atamanın hangi düzeyi hedeflediğini
söylüyor. Bildirim olmadığında hedef her zaman yereldir ve bu, önceki tablodaki
`UnboundLocalError` ile aynı kuralın öbür yüzüdür — biri okumada, öbürü yazmada görünür.

Bu ayrım, dıştaki bir nesneyi **değiştirmekle** dıştaki adı **yeniden bağlamak**
arasındaki farkı da açıklar. Önceki dersteki paylaşılan kova hiçbir bildirim olmadan
büyüyordu, çünkü orada yapılan şey ada atama değil, adın gösterdiği nesneyi değiştirmekti.
Kapsam kuralları adların bağlanmasını yönetir; nesnelerin içeriğini değil.

## Adın Ne Zaman Çözüldüğü

Son tablo zincirin **ne zaman** yürüdüğünü ölçüyor ve buraya kadarki her şeyi tek bir
sonuçta topluyor. Bir döngüde üç işlev üretiliyor; her biri gövdesinde döngü değişkenini
çıplak bir adla okuyor. Döngü bittikten sonra üçü de çağrılıyor.

Beklenen sonuç `[0, 1, 2]`, ölçülen sonuç **`[2, 2, 2]`**. Üç işlev de aynı değeri
döndürüyor.

Nedeni kapsam kuralının kendisidir. İşlevlerin gövdesindeki ad, işlev **üretildiğinde**
çözülmüyor; **çağrıldığında** çözülüyor. Üretim sırasında gövdeye yazılan şey bir değer
değil, bir addır — ve o ad kapsayan gövdedeki tek bir değişkeni gösterir. Üç işlev üç ayrı
değeri değil, **aynı adı** taşıyor. Çağrıldıklarında arama zinciri yürüyor, kapsayan
düzeydeki adı buluyor ve orada döngünün bıraktığı son değer duruyor.

Üçüncü satır o son değerin ne olduğunu gösteriyor: döngü bittikten sonra da ad yaşıyor ve
değeri **2**. Python'da döngü kendi kapsamını açmaz; döngü değişkeni onu çevreleyen
gövdeye aittir ve döngü bitince ortadan kalkmaz. Programlama Temelleri kursu döngü
değişkeninin **yerel** olduğunu söylemişti ve bu doğrudur — ölçüm onu daraltıyor: yerel
olduğu birim döngü değil, **fonksiyon gövdesinin tamamıdır**. Süslü parantezle ya da
anahtar sözcükle kapatılan blokların kendi kapsamını açtığı dillerde bu satır bir hata
verirdi; burada bir değer veriyor.

İkinci satır çözümü veriyor ve çözüm önceki dersin kuralıdır. Ad varsayılan değer olarak
yazıldığında sonuç **`[0, 1, 2]`** oluyor. Varsayılan ifadesi **tanım okunurken** bir kez
değerlendirilir; tanım burada döngü gövdesinde olduğu için her turda yeniden çalışıyor ve
o turdaki değeri yakalıyor. Değer, arama zincirine bırakılmak yerine tanım anında
kopyalanmış oluyor.

İki dersin kuralı burada birleşiyor: kapsam adın **nerede** aranacağını söylüyor,
varsayılanın değerlendirilme zamanı ise **ne zaman** aranacağını değiştiriyor. Aynı üç
satırlık döngü, tek bir imza değişikliğiyle iki ayrı sonuç veriyor.

## Özet

- Ad araması dört düzeyde ve sabit bir sırada yürür — yerel, kapsayan, genel, yerleşik —
  ilk bulduğunda durur ve dördü de bulamazsa `NameError` verir.
- Her düzey kendinden dıştakileri kapatır: aynı ad üç düzeyde tanımlıysa en içteki kazanır
  ve öbürleri aramaya hiç girmez.
- Yerleşik düzeyin arama sırasında ayrıcalığı yoktur; en sonda olduğu için üstteki
  herhangi bir düzeyde aynı adın tanımlanması yerleşiği o gövdede erişilemez kılar.
- Bir adın yerel olmasına karar veren şey okumanın yeri değil, gövdede **bir yerde** ona
  atama yapılmasıdır; atama en sonda olsa bile ad gövdenin başından itibaren yereldir ve
  atamadan önceki okuma `UnboundLocalError` üretir.
- Gövdeden dışarı yazmak bildirimle olur: `nonlocal` atamayı kapsayan düzeye, `global`
  genel düzeye yönlendirir. Bildirimsiz atama dıştakini güncellemez, onu gölgeleyen yeni
  bir yerel ad kurar.
- Gövdedeki bir ad, işlev üretildiğinde değil **çağrıldığında** çözülür: döngüde üretilen
  üç işlev aynı adı paylaştığı için üçü de **`[2, 2, 2]`** döndürür; adı varsayılan değer
  olarak yakalamak sonucu **`[0, 1, 2]`** yapar.

## Sonraki Adım

Arama zincirinin son basamağındaki adlar buraya kadar yalnız gölgelenecek bir şey olarak
göründü. Oysa o düzeyde duran adlar dilin en çok kullanılan işlevleridir ve her biri, ilk
iki dersin ölçtüğü protokollere doğrudan bağlanır: uzunluk soran, metne çeviren, yineleyici
isteyen, doğruluk sınayan, sıralayan. Sonraki ders bu yerleşikleri **sözleşmeleriyle**
ölçer — her birinin hangi özel yöntemi çağırdığını ve o yöntem tanımlı değilse ne olduğunu.
Ortaya çıkan şey, yerleşiklerin iş yapan işlevler değil, **protokol çağıran ince
kabuklar** olduğudur.
