Python'da bir değişkeni fonksiyon dışında kullanmaya çalıştığınızda "neden görünmüyor?" sorusunun cevabı basittir: her fonksiyon kendi local scope adını verdiğimiz kapalı bir kutuda çalışır ve bu kutunun içindekiler dışarıya sızmaz. Python scope kavramı, bir değişkenin programın hangi bölgesinden görülebileceğini belirleyen kurallar bütünüdür; local, global ve nonlocal bu kuralların üç temel katmanıdır. Bu yazıda özellikle yeni başlayanların sık karşılaştığı UnboundLocalError hatasının neden oluştuğunu ve nasıl çözüleceğini, gerçek kod örnekleriyle adım adım göreceksiniz.
Local Scope Nedir? Bir Fonksiyonun Kendi Kutusu
Bir fonksiyon çağrıldığında, Python o fonksiyon için geçici bir çalışma alanı oluşturur. Fonksiyonun içinde tanımladığınız her değişken bu alana, yani local scope'a aittir ve yalnızca o çağrı süresince yaşar. Fonksiyon çalışmayı bitirip geri döndüğü anda bu çalışma alanı tamamen temizlenir; içindeki değişkenler bellekten silinir ve dışarıdan artık erişilemez hale gelir. Bunu, girdiğinizde eşyalarınızı bıraktığınız ama çıkarken hiçbir şey götüremediğiniz bir oda gibi düşünebilirsiniz.
Yeni başlayan bir öğrenci fonksiyon içinde tanımladığı bir değişkeni fonksiyon dışında çağırdığında genellikle şaşırır, çünkü değişken az önce "vardı". Ama aslında o değişken hiçbir zaman fonksiyonun dışına ait olmamıştır. Aşağıdaki örnek bu durumu net biçimde gösterir:
def selamla():
mesaj = "Merhaba, dünya!"
print(mesaj) # Bu satır çalışır, çünkü mesaj local scope içinde
selamla()
print(mesaj) # NameError: name 'mesaj' is not defined
Burada mesaj değişkeni yalnızca selamla() fonksiyonu çalıştığı sürece vardır. Fonksiyon bittiğinde mesaj da yok olur ve son satırdaki print(mesaj) ifadesi Python'a tanıdık gelmez, bu yüzden NameError fırlatılır. Bu davranış bir hata değil, Python'un bilinçli bir tasarım tercihidir: fonksiyonlar birbirinin iç değişkenlerine karışmasın diye her fonksiyon kendi kutusunda çalışır. Local scope mantığını gerçek kod alıştırmalarıyla pekiştirmek isteyenler için birebir Python dersleri bu tür temel kavramları uygulamalı örneklerle anlatan bir başlangıç noktası olabilir. Bir sonraki bölümde, fonksiyonun dışında tanımlanan ve fonksiyonlar arasında paylaşılabilen global scope'u ele alacağız.
Global Scope Nedir? Modül Seviyesindeki Değişkenler
Local scope'un aksine, bir Python dosyasının (modülün) en üst seviyesinde, herhangi bir fonksiyonun dışında tanımlanan değişkenler global scope'ta yaşar. Bu değişkenler programın çalıştığı sürece bellekte kalır ve o dosya içindeki tüm fonksiyonlar tarafından okunabilir. Yani local scope bir fonksiyona özelken, global scope tüm dosyaya aittir.
Burada yeni başlayanların kafasını karıştıran önemli bir ayrım vardır: bir fonksiyon içinden global bir değişkeni okumak serbesttir, ancak o değişkene doğrudan bir değer atamaya çalıştığınızda Python bunu global değişkeni değiştirme isteği olarak değil, o fonksiyona özel yeni bir local değişken oluşturma isteği olarak yorumlar. Bu ayrımı ileride hataların kaynağını anlamak için aklınızda tutmanız gerekecek; şimdilik sadece okuma işleminin sorunsuz çalıştığını görelim:
sehir = "İzmir"
def bilgi_yazdir():
# Sadece okuma yapılıyor, atama yok
print(f"Yaşanılan şehir: {sehir}")
bilgi_yazdir()
print(sehir) # Fonksiyon dışında da erişilebilir
Bu örnekte sehir değişkeni modül seviyesinde tanımlandığı için hem bilgi_yazdir() fonksiyonunun içinden hem de fonksiyon dışından sorunsuzca erişilebilir. Fonksiyon içinde sehir değişkenine herhangi bir yeni değer atanmadığı, yalnızca mevcut değeri okunduğu için Python burada hiçbir çelişki görmez ve global değişkeni doğrudan kullanır. Bu davranış, çoğu programın sabit ayarları veya paylaşılan verileri global düzeyde tutup fonksiyonlarla bu verileri okuyarak işlemesinin temelini oluşturur.
global Anahtar Kelimesi: Kullanımı ve Riskleri

Bir fonksiyon içinden global bir değişkeni sadece okumak değil, değerini değiştirmek de isteyebilirsiniz. İşte tam bu noktada Python'a "bu değişken aslında dışarıdaki global değişken, yeni bir local değişken oluşturma" demeniz gerekir. Bunu sağlayan anahtar kelime global'dır. Ancak bu anahtar kelimeyi unutmak, yeni başlayanların en sık düştüğü tuzaklardan biridir ve doğrudan UnboundLocalError ile sonuçlanır.
Aşağıdaki hatalı örnekte, fonksiyon dışında tanımlanan sayac değişkenini fonksiyon içinde artırmaya çalışıyoruz ama global demeyi unutuyoruz:
# HATALI KOD
sayac = 0
def arttir():
sayac = sayac + 1 # UnboundLocalError!
print(sayac)
arttir()
Burada Python, fonksiyon içinde sayac'a bir atama satırı gördüğü anda onu local değişken olarak kabul eder; fakat aynı satırda sayac'ı okumaya çalıştığınızda bu local değişken henüz bir değere sahip olmadığı için hata verir. Doğru çözüm, global anahtar kelimesiyle Python'a hangi değişkenden bahsettiğinizi açıkça söylemektir:
# DÜZELTİLMİŞ KOD
sayac = 0
def arttir():
global sayac
sayac = sayac + 1
print(sayac)
arttir() # 1
arttir() # 2
global sayac satırı sayesinde fonksiyon artık dışarıdaki değişkeni okuyup üzerine yazabilir. Ancak bu kolaylığın bedeli vardır: global kullanımı arttıkça bir fonksiyonun hangi değişkenleri değiştirdiğini takip etmek zorlaşır, fonksiyonu tek başına test etmek güçleşir çünkü artık davranışı dış dünyadaki bir değişkenin durumuna bağlıdır. Küçük betiklerde veya sayaç, ayar gibi tek bir paylaşılan durumu güncellemek gerektiğinde global makul bir seçimdir; ancak fonksiyonun girdi olarak değer alıp çıktı olarak sonuç döndürmesi çoğu zaman daha anlaşılır ve hatasız bir tasarımdır. Bu tür tasarım kararlarını birebir geri bildirimle netleştirmek isteyenler 1-1 özel ders desteğinden faydalanarak kendi kod örnekleri üzerinden çalışabilir.
nonlocal ve İç İçe (Nested) Fonksiyonlarda Kapsam
Bir fonksiyonun içinde başka bir fonksiyon tanımladığınızda, Python'da iç içe (nested) fonksiyon yapısı oluşur. İçteki fonksiyon, dıştaki fonksiyonun değişkenlerini okuyabilir; ama değiştirmek isterse işler local/global mantığından biraz farklı işler. İşte tam bu noktada devreye nonlocal anahtar kelimesi girer.
def dis_fonksiyon():
sayac = 0
def ic_fonksiyon():
nonlocal sayac
sayac += 1
print("Sayaç:", sayac)
ic_fonksiyon()
ic_fonksiyon()
print("Son değer:", sayac)
dis_fonksiyon()
Burada sayac değişkeni dis_fonksiyon'a ait. ic_fonksiyon içinden nonlocal sayac demek, Python'a "bu değişkeni kendi içimde değil, beni saran bir üst fonksiyonda ara" demektir. Bu, bir fonksiyonun kendi içinde tanımlanmış başka bir fonksiyona sahip veri ve davranışı hatırlamasını sağlayan yapıya kabaca closure denir; şimdilik bunun ne olduğunu bilmeniz yeterli, detaylarına girmeye gerek yok. nonlocal ile global arasındaki fark çok nettir: global her zaman modülün en üst seviyesindeki değişkeni hedefler, nonlocal ise en yakın "sarmalayan" (enclosing) fonksiyon kapsamını hedefler. Yani üç kat iç içe fonksiyonunuz varsa, nonlocal bir üstteki fonksiyona bakar, en dıştaki modül seviyesine değil.
Üçüncü Tipik Hata: nonlocal'i Unutmak
Yeni başlayanların en çok şaşırdığı senaryo, iç fonksiyonda dış fonksiyonun değişkenini nonlocal demeden değiştirmeye çalışmaktır. Python bunu sessizce yeni bir local değişken sanır ve genellikle UnboundLocalError fırlatır:
# HATALI KOD
def sepet_olustur():
toplam = 0
def urun_ekle(fiyat):
toplam = toplam + fiyat # UnboundLocalError!
return toplam
print(urun_ekle(50))
sepet_olustur()
# DÜZELTİLMİŞ KOD
def sepet_olustur():
toplam = 0
def urun_ekle(fiyat):
nonlocal toplam
toplam = toplam + fiyat
return toplam
print(urun_ekle(50))
sepet_olustur()
Bu tarz kapsam hatalarını kod yazmadan önce kavramsal olarak sınamak isteyenler, Python bilgi seviyesini ölçen test ile hangi konularda eksik olduklarını hızlıca görebilir.
LEGB Kuralı: Python Değişkenleri Nasıl Arar

Python bir değişken adıyla karşılaştığında, onu rastgele değil belirli bir sırayla arar. Bu sıralamaya LEGB kuralı denir: Local, Enclosing, Global, Built-in. Python önce en yakın kapsamdan başlar, bulamazsa bir üst kapsama çıkar; bunun mantığı basittir, çünkü en spesifik ve en güncel değeri her zaman en içteki kapsamda aramak, kodun öngörülebilir davranmasını sağlar.
| Aşama | Kapsam | Örnek |
|---|---|---|
| L | Local (yerel) | Fonksiyonun kendi içinde tanımlanan değişken, örn. def f(): x = 1 |
| E | Enclosing (sarmalayan) | İç içe fonksiyonda dış fonksiyonun değişkeni, nonlocal ile erişilen değer |
| G | Global (modül seviyesi) | Dosyanın en üstünde tanımlanan değişken, global ile değiştirilen değer |
| B | Built-in (yerleşik) | len, print, range gibi Python'a hazır gelen isimler |
Python bu dört aşamayı sırayla tarar ve ismi ilk bulduğu yerde durur; aramaya devam etmez. Bu yüzden bir fonksiyon içinde print gibi bir ismi kendi değişkeniniz olarak tanımlarsanız, o fonksiyon içinde artık yerleşik print fonksiyonuna değil sizin tanımınıza ulaşılır. LEGB kuralını bilmek, "bu değişken buradan mı geliyor yoksa şuradan mı?" sorusunu sorduğunuz her hata ayıklama anında size net bir kontrol listesi verir: önce en içe bakın, sonra sırayla dışa çıkın.
Yeni Başlayanların Sık Yaptığı Scope Hataları
Local, global ve nonlocal kavramlarını tek tek anlamak yetmez; bu kavramların birbirine karıştığı tipik hata kalıplarını tanımak, gerçek kodda zaman kazandırır. Aşağıdaki liste, fonksiyonlarla yeni tanışan öğrencilerin en sık düştüğü tuzakları özetler:
- Fonksiyon içinde bir global değişkeni
globaldemeden doğrudan değiştirmeye çalışmak veUnboundLocalErrorile karşılaşmak. - Aynı isimde yanlışlıkla yeni bir local değişken oluşturup, aslında global değişkeni güncellediğini sanmak.
- İç içe fonksiyonlarda dış fonksiyonun değişkenini değiştirmek isterken
nonlocalanahtar kelimesini unutmak. - Gerçekten gerekmediği hâlde neredeyse her değişkeni global yapmak ve kodun hangi fonksiyonun neyi değiştirdiğini takip edilemez hâle getirmek.
İkinci maddedeki hata özellikle sinsidir çünkü program hata vermez, sadece beklenmedik sonuç üretir:
# HATALI KOD - global sanıp aslında yeni local oluşturuyor
puan = 0
def puan_ekle():
puan = puan + 10 # Bu satır aslında yeni bir local 'puan' ister
print("Fonksiyon içi puan:", puan)
puan_ekle()
print("Global puan:", puan) # Beklenmedik şekilde hâlâ 0
# DÜZELTİLMİŞ KOD
puan = 0
def puan_ekle():
global puan
puan = puan + 10
print("Fonksiyon içi puan:", puan)
puan_ekle()
print("Global puan:", puan) # Artık doğru şekilde 10
Bu tür hataları kodu çalıştırmadan önce fark edebilmek, pratikle gelişen bir beceridir. Kendi seviyenizi ölçmek ve hangi scope senaryolarında zorlandığınızı görmek isterseniz ücretsiz kodlama bilgisi testini deneyebilirsiniz; sonuçlar hangi konuya daha çok zaman ayırmanız gerektiğini net biçimde gösterir.
Scope Hatalarını Adım Adım Düzeltme Rehberi
Bir UnboundLocalError ya da beklenmedik bir değer gördüğünde panik yapmana gerek yok. Scope hataları neredeyse her zaman aynı mantıkla çözülür: önce hatanın nerede oluştuğunu, sonra hangi değişkenin hangi kutuda yaşadığını bulursun. Aşağıdaki sırayı izlediğinde, karmaşık görünen bir hata birkaç dakikada anlaşılır hâle gelir.
- Hata mesajını dikkatlice oku. Python genellikle hatanın hangi satırda ve hangi değişken adıyla oluştuğunu söyler; bu bilgiyi atlamadan not al.
- Değişkenin nerede tanımlandığını bul. İlgili isim fonksiyonun içinde mi atanıyor, dışarıda mı, yoksa bir üst fonksiyonda mı — bunu belirlemeden doğru çözümü seçemezsin.
- Fonksiyon içinde hem okuma hem atama yapılıp yapılmadığını kontrol et. Atama varsa ve dışarıdaki değeri değiştirmek istiyorsan bu,
globalya danonlocalgerektiren bir durumdur. - Doğru anahtar kelimeyi seç: değişken modül seviyesindeyse
global, bir dış fonksiyonun local scope'undaysanonlocalkullan. İkisi de gerekmiyorsa muhtemelen parametre veyareturnile çözüm daha uygundur. - Düzeltmeyi uyguladıktan sonra kodu küçük, izole bir örnekle test et; fonksiyonu tek başına çağırıp beklenen çıktıyı aldığından emin ol.
- Aynı hatanın başka fonksiyonlarda tekrarlanıp tekrarlanmadığını kontrol et; bir kez öğrenilen scope mantığı genellikle projedeki birden fazla noktada aynı şekilde düzeltilebilir.
Bu adımları uygularken sıkça karşılaşılan dördüncü bir tipik hata daha var: sorunu çözmek için her değişkeni global yapmak. Bu, kısa vadede hatayı susturur ama fonksiyonları birbirine bağımlı, test edilmesi zor bir yapıya sokar.
# Hatalı: Her şeyi global yaparak "çözmek"
counter = 0
total = 0
name = ""
def process(x, y, n):
global counter, total, name
counter += 1
total += x + y
name = n
print(total)
process(3, 4, "Ali")
print(counter, total, name)
# Düzeltilmiş: Parametre ve return ile sadeleştirme
def process(x, y, n, counter, total):
counter += 1
total += x + y
name = n
print(total)
return counter, total, name
counter, total = 0, 0
counter, total, name = process(3, 4, "Ali", counter, total)
print(counter, total, name)
İkinci versiyonda fonksiyon artık dışarıdaki hiçbir değişkene doğrudan dokunmuyor; tüm veriyi parametre olarak alıyor, sonucu return ile geri veriyor. Bu tür alıştırmaları düzenli tekrar etmek istersen Python konularını adım adım işleyen yazılar üzerinden benzer örnekleri inceleyebilirsin.
Scope Yönetiminde İyi Pratikler ve Sonraki Adımlar
Scope hatalarından tamamen kaçınmanın en garanti yolu, fonksiyonları mümkün olduğunca parametre alıp değer döndüren bağımsız birimler olarak tasarlamaktır. Bir fonksiyon global bir değişkene ne kadar az bağımlıysa, onu başka bir yerde tekrar kullanmak, test etmek ve içindeki hatayı bulmak o kadar kolaylaşır. Global değişkenleri yalnızca gerçekten paylaşılan, uygulama genelinde sabit kalması gereken ayarlar için saklamak iyi bir alışkanlıktır. Fonksiyon yazarken kendine şu soruyu sorman faydalı olur: "Bu değeri dışarıdan parametre olarak alabilir miyim, sonucu return ile verebilir miyim?" Çoğu zaman cevap evet olur ve bu, kodu hem daha okunabilir hem de scope hatalarına karşı daha dayanıklı hâle getirir.
Local, global ve nonlocal kavramları ilk öğrenildiğinde soyut kalabilir; gerçek anlam ancak kendi hatalarını kod üzerinde görerek oturur. Bu yüzden küçük fonksiyonlar yaz, bilerek UnboundLocalError tetikle, sonra düzelt — bu tekrar süreci LEGB mantığını kalıcı hâle getirir. Düzenli ve kategorize edilmiş alıştırmalarla ilerlemek istiyorsan, günlük akıllı sorularla çalışmanı destekleyen Soru Avcısı sistemi tam bu noktada işine yarar; scope gibi kavramlar üzerine hazırlanmış sorularla kendi seviyeni ölçebilir, eksik kaldığın noktaları görebilirsin.
Bu konuyu daha sistemli, geri bildirimli bir ortamda pekiştirmek istersen birebir Python eğitimi kapsamında fonksiyonlar, scope ve daha ileri konular üzerinde adım adım ilerleyebilirsin. Unutma, scope kavramını bir kez gerçekten anladığında, bundan sonra yazacağın her fonksiyon çok daha öngörülebilir ve hatasız olacak; bu, yazılım yolculuğunda geri dönüp bakacağın küçük ama önemli bir dönüm noktası olur.
Sık Sorulan Sorular
Fonksiyon içinde tanımladığım değişkeni neden fonksiyon dışında kullanamıyorum?
Çünkü fonksiyon içinde tanımlanan her değişken, o fonksiyona özel local scope'ta yaşar ve fonksiyon çalışmasını bitirdiğinde bu scope tamamen silinir; dışarıdan erişim mümkün değildir.
UnboundLocalError hatası tam olarak neden oluşur?
Bu hata, bir fonksiyon içinde bir değişkene atama yapıldığı için Python'ın o değişkeni otomatik olarak local kabul etmesinden, ancak atama satırından önce aynı isim okunmaya çalışıldığında henüz local scope'ta bir değer bulunmamasından kaynaklanır.
global ve nonlocal anahtar kelimeleri arasındaki fark nedir?
global, bir fonksiyon içinden doğrudan modül seviyesindeki (en dış) değişkene erişip onu değiştirmeyi sağlarken, nonlocal yalnızca iç içe geçmiş fonksiyonlarda, bir dış fonksiyonun local scope'undaki değişkeni hedefler; global scope'a dokunmaz.
Her fonksiyonda global kullanmak kötü bir alışkanlık mı?
Sürekli global kullanmak fonksiyonları birbirine sıkı bağımlı hâle getirir ve hata ayıklamayı zorlaştırır; bunun yerine veriyi parametre olarak almak ve sonucu return ile döndürmek genellikle daha sürdürülebilir bir yaklaşımdır.
LEGB kuralı hata ayıklamama nasıl yardımcı olur?
LEGB sırasını bildiğinde, Python'ın bir ismi ararken hangi scope'lara sırayla baktığını takip edebilir, değişkenin neden beklediğin değeri taşımadığını veya neden bulunamadığını daha hızlı tespit edebilirsin.
nonlocal kullanmak için fonksiyonun mutlaka iç içe mi olması gerekir?
Evet, nonlocal yalnızca bir fonksiyonun başka bir fonksiyonun içinde tanımlandığı durumlarda anlamlıdır; en dış (modül) seviyesindeki bir fonksiyonda nonlocal kullanmak hataya yol açar çünkü işaret edeceği bir dış local scope yoktur.
Closure ile nonlocal arasındaki ilişki nedir?
Closure, bir iç fonksiyonun dış fonksiyonun scope'undaki değişkenleri hatırlamasıyla oluşur; nonlocal ise bu hatırlanan değişkeni yalnızca okumakla kalmayıp iç fonksiyon içinden değiştirmek istediğinde devreye giren anahtar kelimedir.
Local, global ve nonlocal kavramlarını netleştirdikten sonra artık fonksiyonlarını çok daha bilinçli tasarlayabilirsin; sıradaki adım bu bilgiyi küçük alıştırmalarla pekiştirmek olabilir. Python bilgi testi ile scope dâhil temel konulardaki seviyeni ücretsiz olarak ölçebilirsin.