• Sonuç bulunamadı

Fonksiyonların Kapsamı ve global Deyimi

10.5 ˙Isimli Argümanlar

10.9 Fonksiyonların Kapsamı ve global Deyimi

Bu bölümde Python’daki “isim alanı” (namespace) ve kapsam (scope) kavramından söz ede-ce˘giz biraz... Kabaca ifade etmek gerekirse “isim alanı” denen ¸sey, Python’daki herhangi bir nesnenin etki alanıdır. Python’daki nesnelerin birer kapsama alanı vardır. Örne˘gin Python’daki fonksiyonlar birer nesnedir. Esasında Python’daki her ¸sey bir nesnedir. ¸Simdilik bu “nesne”

meselesini fazla kafanıza takmayın. Bu konuyu yeri geldi˘ginde esaslı bir ¸sekilde inceleye-ce˘giz... Ne diyorduk? Evet, Python’daki fonksiyonlar birer nesnedir ve bu nesnelerin de bir kapsama alanı vardır. Ya da ba¸ska bir deyi¸sle fonksiyonlar belirli bir isim alanı içinde yer alır.

Hemen ufak bir örnek verelim:

def deneme():

sayı = 5 print(sayı)

Burada “sayı” adlı de˘gi¸sken, deneme() adlı fonksiyonun isim alanı içinde yer alır. Yani bu de˘gi¸skenin kapsamı deneme() adlı fonksiyonla sınırlıdır. “sayı” adlı de˘gi¸sken bu fonksiyonun dı¸sında var olamaz. Peki bu ne anlama geliyor? Yukarıdaki kodlara ¸söyle bir ekleme yaparak durumu birazcık da olsa somutla¸stıralım:

def deneme():

sayı = 5 print(sayı) print(sayı)

Bu kod parçasını çalı¸stırdı˘gımızda Python bize ¸söyle bir hata mesajı gösterecektir:

NameError: name ’sayı’ is not defined Yani:

˙IsimHatası: "sayı" ismi tanımlanmamı¸s

Halbuki biz “sayı” adlı de˘gi¸skeni deneme() adlı fonksiyonun içinde tanımlamı¸stık, de˘gil mi?

Evet, biz bu de˘gi¸skeni “deneme” adlı fonksiyon içinde tanımlamı¸stık. Ama önümüzde ¸söyle bir gerçek var: Bu bölümün ba¸sında da söyledi˘gimiz gibi, Python’daki nesnelerin bir kapsama alanı vardır. Yani bu nesneler bir isim alanı içinde yer alır. Dolayısıyla “sayı” adlı de˘gi¸skenin kapsamı deneme() adlı fonksiyonun isim alanı ile sınırlıdır. Yani bu de˘gi¸sken deneme() adlı fonksiyonun dı¸sında var olamaz... Bu “deneme” fonksiyonunun kapsama alanı da fonksiyonun içi ile sınırlıdır.

¸

Simdi ¸suna bir bakalım:

def deneme():

sayı = 5

print("deneme() fonksiyonu içindeki sayı: ", sayı) sayı = 10

print("deneme() fonksiyonu dı¸sındaki sayı: ", sayı) deneme()

Gördü˘günüz gibi, “sayı” adlı de˘gi¸skeni fonksiyon dı¸sında da kullanabilmek için, bu de˘gi¸skeni fonksiyonun dı¸sında da tanımlamamız gerekiyor. Yukarıda iki farklı de˘gerle gösterilen “sayı”

adlı de˘gi¸skenler farklı isim alanları içinde yer aldı˘gı için, aynı ada sahip olmalarına ra˘gmen birbirlerine karı¸smıyorlar. Aslında “isim alanı” kavramı çok güzel bir özelliktir. Büyük program-lar yazarken isim alanı kavramının çok i¸sinize yaradı˘gını göreceksiniz. Bu kavram sayesinde de˘gi¸skenlerin birbirine karı¸smasını önleyebiliyoruz. Hele bir de aynı program üzerinde farklı ki¸siler çalı¸sıyorsa, bu “isim alanı” özelli˘gi hayat kurtarıcı olabilir...

Ancak bazı durumlarda bir isim alanı içinde yer alan bir de˘gi¸skene o isim alanı dı¸sından da eri¸sebilmeniz gerekebilir. Mesela ¸söyle bir ¸sey yazmak isteyebilirsiniz:

def sor():

sayı1 = int(input("bir sayı: ")) sayı2 = int(input("ba¸ska bir sayı: ")) def topla():

Burada sayı alma ve alınan bu sayıları toplama i¸slemleri için ayrı birer fonksiyon olu¸sturduk.

Yukarıdaki yapıya göre, sor() fonksiyonu içinde geçen “sayı1” ve “sayı2” adlı de˘gi¸skenleri topla() fonksiyonu içinde i¸sleme tabi tutabilmemiz gerekiyor. Ancak burada bir problem var. Python’un yapısı gere˘gince, sor() ve topla() adlı fonksiyonlar farklı isim alanlarına, dolayısıyla da farklı kapsamlara sahip... Bundan ötürü, bu iki fonksiyon içindeki de˘gi¸skenlere dı¸sarıdan eri¸semiyoruz. Zaten yukarıdaki kodları çalı¸stırdı˘gımızda Python bize bununla ilgili bir hata mesajı gösterecektir...

Yukarıdaki sorunu a¸sabilmek için Python bize global adlı bir araç sunuyor... global deyimi yardımıyla, bir isim alanı içindeki de˘gi¸skenlere o isim alanı dı¸sından da eri¸sebiliyoruz. Mesela yukarıdaki örne˘gi ¸söyle yazalım:

def sor():

global sayı1 global sayı2

sayı1 = int(input("bir sayı: ")) sayı2 = int(input("ba¸ska bir sayı: ")) def topla():

Bu kodların ba¸sına ekledi˘gimiz “global sayı1” ve “global sayı2” ifadeleri sayesinde “sayı1” ve

“sayı2” adlı de˘gi¸skenlere fonksiyon dı¸sından da eri¸silebilmesini sa˘glıyoruz. Yukarıdaki kodları çalı¸stırdı˘gımızda artık programımız hatasız bir ¸sekilde görevini yerine getirecektir. Sayı dı¸sında bir de˘ger girilmesi durumunda dahi programımızın çökmemesi içintry... except... blok-larından yararlandı˘gımıza dikkat ediyoruz...

Bu arada e˘ger istersek yukarıdaki “global sayı1” ve “global sayı2” ifadelerini birle¸stirebiliriz:

def sor():

global sayı1, sayı2 ...

...

Gelin isterseniz tanıdık bir program üzerinde uygulayalım ö˘grendiklerimizi...

def sor():

global sayı1 global sayı2

sayı1 = int(input("bir sayı: ")) sayı2 = int(input("ba¸ska bir sayı: ")) def topla():

print(sayı1 + sayı2) def çıkar():

print(sayı1 - sayı2) def çarp():

print(sayı1 * sayı2)

seçenek = input("Yapmak istedi˘giniz i¸slem: ") if seçenek == "5":

Gördü˘günüz gibi,global deyimi epey i¸se yarıyor. Ancak size bu deyimle ilgili kötü bir haberim var. Bu deyim ne kadar faydalıymı¸s gibi görünse de aslında ço˘gu zaman i¸sleri karı¸stırabiliyor.

¸

Söyle bir örnek verelim:

a = 5

def de˘gi¸skeni_de˘gi¸stir():

a = 10

print("bu de˘gi¸sken fonksiyon içinde: ", a)

de˘gi¸skeni_de˘gi¸stir()

print("bu de˘gi¸sken fonksiyon dı¸sında: ", a)

Bu kodları çalı¸stırdı˘gımızda ¸söyle bir çıktı alıyoruz:

bu de˘gi¸sken fonksiyon içinde: 10 bu de˘gi¸sken fonksiyon dı¸sında: 5 Bir de ¸suna bakalım:

a = 5

def de˘gi¸skeni_de˘gi¸stir():

global a

a = 10

print("bu de˘gi¸sken fonksiyon içinde: ", a)

de˘gi¸skeni_de˘gi¸stir()

print("bu de˘gi¸sken fonksiyon dı¸sında: ", a)

Bu kodlar ise bize ¸söyle bir çıktı veriyor:

bu de˘gi¸sken fonksiyon içinde: 10 bu de˘gi¸sken fonksiyon dı¸sında: 10

Gördü˘günüz gibi, fonksiyon içindeki i¸slem fonksiyonun dı¸s bölgesini de etkiledi ve normalde de˘geri “5” olması gereken “a” adlı de˘gi¸skeni de˘gi¸sikli˘ge u˘grattı. global deyimi bu özelli˘ gin-den ötürü hiç beklenmedik bir anda programınızı allak bullak edebilir. Özellikle büyük boyutlu ve birden fazla ki¸sinin üzerinde çalı¸stı˘gı programlardaglobal deyimi züccaciye dükkanına fil girmi¸s gibi bir etki yaratabilir... O yüzden Python programcıları genellikleglobal deyimini kul-lanmaktan kaçınır. Hatta Python camiasında ¸söyle bir söz vardır: “E˘ger yazdı˘gınız programda global deyimini kullanmanız gerekti˘gini dü¸sünüyorsanız, programınızı gözden geçirmenizin zamanı gelmi¸s demektir!”

Python’da global yerine benimseyebilece˘gimiz daha sa˘glıklı yollar vardır. Mesela sınıflı yapıları kullanmak gibi... Hiç endi¸se etmeyin. Yeri geldi˘ginde sınıflı yapıları da enine boyuna inceleyece˘gimizden emin olabilirsiniz. Pekiglobal deyimini hangi durumlarda kullanmamızın bir sakıncası yoktur? Esasında, dedi˘gimiz gibi, en iyisi ki¸sinin kendini global deyimine hiç alı¸stırmamasıdır. Ama e˘ger u˘gra¸stı˘gınız kod ufak boyutlu bir ¸seyse ve sizden ba¸ska kimsenin bu kodlar üzerinde çalı¸smayaca˘gından eminseniz, o anda kar¸sıla¸stı˘gınız bir sorunu çözmek için global deyimine ba¸svurmayı tercih edebilirsiniz... Elbette global deyimini kullanmak günah de˘gildir! Sadece, bunu kullanmak iyi bir programcılık tekni˘gi olarak kabul edilmez...