11B: Değişken Kapsamı

11. derste bulunan A, B, C bölümlerini istediğiniz sırayla tamamlayabilirsiniz.

Bu derste değişken kapsamı olarak adlandırılan bir kavramı ele alacağız. Ana fikir, iki farklı değişkene farklı kapsamlarda yer aldıkları her durumda aynı ismin verilebilmesidir. Bu, özellikle de geniş çaplı programları yazmayı ve düzenlemeyi kolaylaştırır. Ayrıca bu kavrama, daha ileride göreceğimiz yineleme konusunda ihtiyacımız olacak.

Değişken Kapsamına Bir Örnek

Bu örnekte kullanacağımız programın bir bölümü şöyle:

def kare(x):
   değer = x * x
   return değer
Bu, x, sayısının karesini hesaplayan bir fonksiyon, yani kare(5) return sonucu 25 olacak. Şimdi diyelim,  kare fonksiyonunu, programın değer  adlı değişkeni başka bir amaçla kullandığı bir bölümünde tekrar çağırdık:

# Programın ana gövdesi burada başlıyor
değer = 17
beşinKaresi = kare(5)
print(beşinKaresi, değer)
Soru şu, program çıktı olarak ne yazdıracak? İki ihtimal var, eğer Python'un nasıl çalıştığını bilmiyorsak:

  1. Birinci ihtimal, Python iki değer değişkeninin bir şekilde ayrı tutulması gerektiğini anlayacak. Böylece kare 25 sonucunu verirken, değer değişkeni ana gövdede 17 olduğu gibi kalacak, ve program 25 17 sonucunu verecek.
  2. Diğer ihtimal de, kare fonksiyonu işleme konduğunda  değer değişkeninin mevcut karşılığı yerine 25 getirilecek ve sonuç olarak da program 25 25 çıktısını verecek.

Bakalım gerçekte ne olacak!

Python 1. ihtimale göre davranacaktır. Çünkü, bir fonksiyon çağrıldığı zaman, fonksiyonun dışında tanımlanmış hiçbir değişken etkilenmez. Değişkenlere atanmış değerler sadece "yerel" işlemleri, yani fonksiyonun "içindeki" işlemleri etkiler. Python ve diğer çoğu programlama dillerinde bunu yapabilmemizin sebebi; bu şekilde içinde pek çok fonksiyon bulunan çok uzun programları daha basit olarak yazabiliriz. Yeni bir fonksiyon tanımladığımızda, fonksiyonun içinde herhangi bir değişken adını (result, temp vei gibi son derece genel kelimeler de dâhil) kullanmaya her zaman izin verilir, isterse bu değişkenler programın başka yerlerinde, hatta başka fonksiyonların içinde defalarca kullanılmış olsun.

Bunu detaylı olarak görmek için, görüntüleyicide 8 adımın 6.sına bakabilirsiniz. Burada değer adıyla tanımlanmış iki farklı değişken göreceksiniz; bir tanesi kare fonksiyonunun içinde diğeri de dışarıda ("global" kısımda).

Multiple Choice Exercise: İç ve Dış
Bu program hangi çıktıyı verir?

x = "dış"
def xDeğiş(değer):
x = değer
xDeğiş("iç")
print(x)
Doğru! x = değer ifadesi sadece x değişkeninin yerel versiyonudur ve sadece fonksiyonun içinde geçerlidir. x değişkeninin global versiyonu değişmez. (Yani, xDeğiş fonksiyonunun hiçbir etkisi olmayacaktır.)

Kapsama (scope) benzeyen başka bir kavram da isim alanıdır (namespace); isim alanı paketin kapsamı gibidir. Diyelim bir yerde x  değişkenini kullanan bir paket ithal (import) ederseniz (math matematik gibi), buradaki x  hiçbir şekilde programın diğer yerlerindeki x  değişkeni ile karışmaz, çünkü farklı isim alanlarında yer almaktadırlar.

Kapsama Kuralları: Dışarı Yolla

Bazı durumlarda lokal ve global kapsamdaki değişkenleri birlikte kullanmak isteyebiliriz. Yaygın bir örnek olarak, programın ilk kısmında oluşturduğunuz genel bazı değişkenlerin fonksiyonunuzun içinde de okunmasını istersiniz.

Example
Global değişkeni fonksiyonun içinde okumak

Burada, yerel kapsamda neliPizza diye bir değişkenimiz yok, ama bu bir hataya yol açmıyor. Python, değişkenleri ele alırken, eğer bir değişken, kendisine ihtiyaç duyulan lokal kapsamda yer almıyorsa, onu global kapsamda arar. Bizim örneğimizde neliPizza değişkeni global kapsamda var. (Bir fonksiyon gövdesinin başka bir fonksiyon gövdesini çağırdığı daha genel bir durumda, bu kez üç kapsam elde ederiz; Python daima önce "en yerel" olanı denetler ve değişkeni bulana kadar adım adım kapsamları tarar.)

Yukarıdaki örneklerin ikisi, pizzaSiparişi ve xDeğiş, fonksiyonları sentaks olarak aynıdır. Pekiyi, Python xDeğiş fonksiyonunda yeni bir lokal değişken olarak x değişkenini yaratırken, yeni bir neliPizza değişkenini pizzaSiparişi fonksiyonu için neden oluşturmadı? Python'un bu konudaki kuralı şöyledir: Eğer değişkeni sadece okuyorsanız, yeni lokal değişken yaratılmaz; ama eğer değişkeni en az bir kez de olsa yazdıysanız, değişken tüm fonksiyon gövdesi boyunca lokal kapsamda değerlendirilir. (Bu durum UnboundLocalError hatasının en yaygın sebebidir: Python resmi sayfalarında yer alan şu iki soruya göz atın [1, 2].)

Fonksiyon argümanları her zaman lokal değişken olarak kabul edilir. Buradaki kırık program parçasından görebilirsiniz (g değişkenini 0 olarak resetlemeye çalışıyor ama işe yaramıyor).

global Değişiklikler

Diğer pek çok şey gibi, yukarıda anlatılan normal akış tüm durumların %99'u için geçerlidir, ama kalan %1'lik durumlar için bir fonksiyon içine yerleştirdiğiniz global bir değişkenin yerine başka bir isim seçmeniz gerekebilir. Python'da bunu global bir ifade kullanarak yapabilirsiniz.

Yukarıda geçen xDeğiş örneğini burada farklı bir şekilde yazdık; değişkeni fonksiyon içinde global olarak ilan etmek, değişkenin global değerini fonksiyonun içinden değiştirmemize izin verir.

Bir fonksiyonun içerisinde global kapsamda tanımlanmış bir değişkene bir değer atadığımızda; global değişken güncellenmiş olmaz, sadece lokal kapsamda aynı isimle yeni bir değişken yaratılmış olur. Eğer global kapsamlı değişkenin değerini fonkisyon içinde güncellemek isterseniz, fonksiyonun içerisinde "global <değişken adı>" ifadesini kullanmanız gerekir. Böylece Python, değişkenin değerinde yaptığımız değişikliğin global kapsamdaki değişken için de geçerli olacağını anlar. Dersimizi bu bilgi ile bitiriyoruz!