Python Programlama Dili

Bölüm 2

Genel Yöntemler

Top Navigasyon

Ders 14

2.3 - Fonksiyonların Uygulanması

Python programlama dilinde fonksiyonların kullanımı için, seksiyon 1.8 de tanıtım bilgileri verilmişti. Bu kısımda ise daha geniş olarak fonksiyonların kullanımı üzerinde duracağız.

Burya kadar aldığımız bilgilerden, fonksiyonların önemini görebiliyoruz. Fonksiyonlar hem kendi başlarına kapalı bir birim olarak bazı işlevlerin yerine getirilmesi, hem Python modüllerinin yazımı, hem nesne (object) lerin metotlarının oluşturulması açısından büyük önem taşımaktadırlar. Fonksiyonlar, programların yapı taşlarını oluştururlar.

2.3.1 - Fonksiyonların Değişkenlere Atanması

Python programlama dilinde fonksiyonlar birinci sınıf nesnelerdir ve değişkenlere atanabilirler. Örnek :

      g = adSoyad;

Bu atamada fonksiyonun sadece yazılımı, g değişkenine yüklenmiş fakat, fonksiyon çalışmamıştır. Eğer fonksiyon çalışmış olsaydı, g değişkeninde fonksiyon yazılımı değil, geri döndürdüğü değer atanmış olurdu. Yukarıdaki atama gerçekleştikten sonra, artı g değişkeni de, kendisine atanan fonksiyonun aynı olur ve fonksiyon çalıştırma işlemcisi eklenerek g() şeklinde çalıştırılabilir. Bu ifade, sanki adSoyad() yazılmış gibi aynı işlevi yapar ve aynı değeri döndürür.

2.3.2 - Fonksiyonların Sözdizimi

Fonksiyonların ilk tanıtımlarının yapılmış olduğu seksiyon 1.8 de fonksiyon yazılımının EBNF formülasyonu verilmişti. Burada bu formülasyonu hatırlatma amacı ile yeniden incelemek, bir tür haritadan yararlanmak gibi gerekli olacaktır.

Python için fonksiyon tanımı EBNF formülasyonu şekli,

funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite
decorators ::= decorator+
decorator ::= "@" dotted_name ["(" [parameter_list [","]] ")"] NEWLINE
dotted_name ::= identifier ("." identifier)*
parameter_list ::= (defparameter ",")*
| "*" [parameter] ("," defparameter)* ["," "**" parameter]
| "**" parameter
| defparameter [","] )
parameter ::= identifier [":" expression]
defparameter ::= parameter ["=" expression]
funcname ::= identifier

şeklindedir.

Yukarıdaki formülasyondan, Python programlama dilinde, fonksiyon sözdiziminin (sentaks) büyük bir kısmının isteğe bağlı olduğu, sadece az bir zorunlu kısmının bulunduğu görülebilir. Zorunlu olan,

   "def" funcname "("")"":" suite 

kısmıdır ve bunun da uygulanması,

  def birFonksiyon():
  fonksiyon içeriği ...

şeklindedir. Doğal olarak, fonksiyon içeriği olmazsa, fonksiyon tanımına da gerek kalmayacaktır.

2.3.3 - Fonksiyonların Uygulanma Yöntemleri

Aşağıda görülen programda adSoyad(ad,soyad) fonksiyonu,, Python program dilinde minimal bir sözdizimi uygulanarak yazılmış, ve bu fonksiyon, çeşitli yöntemler kullanılarak çağrılmıştır.

  # Program : Ders14program1.py
    	
  def adSoyad(ad  , soyad  ):
    	
  if len(ad) == 0 and len(soyad) == 0 :
  adıVeSoyadı = "Adı ve Soyadı Belirtilmemiştir!";
          
  else:
  adıVeSoyadı = ad  + ' '  + soyad; 

return adıVeSoyadı; print("Adı ve Soyadı : " , adSoyad("" , ""); print("Adı ve Soyadı : " , adSoyad('Güneş' , 'Tezel'); print("Adı ve Soyadı : " , adSoyad(soyad = 'Tezel' , ad = 'Güneş');

---------Program----Sonucunun----Görüntülenmesi---------------------------- Adı ve Soyadı : Adı ve Soyadı Belirtilmemiştir! Adı ve Soyadı : Güneş Tezel Adı ve Soyadı : Güneş Tezel

Fonksiyonların argümanları, formal parametrelerdeki sıralar kullanılarak yapılabilir. Bu tür bir uygulama, hemen hemen tüm program dilleri için genel bir fonksiyon çağırma şeklidir. Yukarıdaki programda, ilk iki print() bildiriminde adSoyad() fonksiyonun çağrılması, fonksiyondaki parametrelin tanım sıraları gözetilerek yapılmıştır.

Python programlama dilinde istendiğinde, fonksiyonların çağrılmalarında, argümanların formal parametrelerde belirtilmiş olan isimleri kullnılarak ve istendiğinde, formal parametrelerin tanım sıraları gözetilmeden çağrılmaları yaılabilir. Yukarıdaki programda, üçüncü print() fonkisyonu içinde, adSoyad() fonksiyonun çağrılması bu yöntemle gerçekleştirilmiştir.

Yukarıdaki programda, len(ad) ifadesi, öntanımlı len() fonksiyonu kullanılarak, ad sözel verisinde karakter sayısının (veri uzunluğunun) saptanmasını sağlamaktadır.

Yukarıdaki programda, adıVeSoyadı değişkeni, fonkiyon içinde tanımlanmıştır. Dolayısı ile, bu bir yerel değişkendir ve sadece fonksiyon içinde tanımlıdr. Bu değişken, fonksiyon dışında tanımsızdır ve fonksiyon dışından erişime kapalıdır.

Python programlama dilinde, değişkenlerin üç tür kapsam alanları bulunabilir:

Aşağıdaki program, global, yerel ve yerel olmayan kapsamlar üzerinde açıklayıcı uygulamalar içermektedir.

  # Ders14program2.py
  
  a = 11; # global kapsam
  
  def dışFonksiyon():
  b = 23;
  """dışFonksiyon açısından yerel(lokal),  
içFonksiyon açısından nonLocal (yerel olmayan) kapsam,
dışFonksiyon kapsamı dışında tanımsız."""
def içFonksiyon(): global a; # Global değişken a ya bağlandı! a = 919; # Global değişkenin değeri değişti! nonlocal b; # Yerel olmayan değişken b ya bağlandı! b = 645; # Yerel olmayan değişkenin değeri değişti! c = 35; # Yerel değişken tanımı global x; # Yeni bir global değişken tanımı x = 99; # Yeni global değişkene değer bağlanması içFonksiyon(); if b != 23: s1 = 'Bu Değişkenin Değeri bir alt program\n'; s2 = 'tarafından değiştirilmiştir ve \n'; s3 = 'güncel değeri,'; global s;
s = s1 + s2 + s3; print(s + ' b =' , b , 'dir.\n'); dışFonksiyon(); if not a == 11: print(s + ' a =' , a , 'dir.\n'); print ('x = ', x); ---------Program----Sonucunun----Görüntülenmesi---------------------------- Bu Değişkenin Değeri bir alt program tarafından değiştirilmiştir ve güncel değeri, b = 645 dir. Bu Değişkenin Değeri bir alt program tarafından değiştirilmiştir ve güncel değeri, a = 919 dir. x = 99

Yukarıdaki program üzerine, açıklanması gereken çok nokta bulunmaktadır. İlk olarak, global program alanı altında, bir dışFonksiyon() tanımlanmış ve bu dış fonksiyon içinde, bir de içFonksiyon() tanımlamıştır. Tanımlanmış olan içFonksiyon() içeriğine, global program alanı tarafından erişim olanağı yoktur.

Global program alanı içinden tanımlanan a değişkeni, global bir değişkendir ve değerine, gerek içFonksiyon(), gerekse dışFonksiyon() içinden erişilebilir. Erişim sınırlıdır. Global değişkenlerin değerlerine, bir alt program isim alanı içinden erişilebilir. Değerleri okunabilir ve eğer global değişken, değiştirilebilir (mutable) bir tip ise değerine ekleme çıkarma yapılabilir. Fakat, hiçbir koşul altında, veri tipi ne olursa olsun, global değişkenler, alt program isim alanları içinden ne del bildirimi ile yok edilebilirler ne de kendilerine yeni bir değer atanabilir.

Global bir değişken ile aynı ad ile, bir alt program isim alanında, yani bir değişken tanımlanabilir ve bu değişkene yeni bir değer atanabilir Böyle bir durumda, tanımlanan bu değişken, yerel bir değişken olacaktır. Bu değişkene atanan değer, sadece atandığı alt fonksiyonun isim (tanım) alanında geçerli olacaktır. Bu değişken atandığı alt program isim alanında yok edildiği takdirde, yoketme sadece bu alt fonksiyon isim alanı ile sınırlı kalacaktır. Bu değişken bundan sonra tanımlandığı isim alanında tanımsız olacaktır. Fakat alt fonksiyon isim alanı terkedildiğinde, global isim alanına geçildiğinde, global değişken tanımlanmış olduğu değer ile tanımlı olarak kalacaktır. Bu dokunulmazlık, Python programlama dilinde, global değişkenlerin değerlerinin kontrolsüz olarak değiştirilememesi için konulmuş olan, bir tür sigorta gibidir. Ama yeterli değildir.

Global değişkenlerin alt programlar içinden dokunulmazlığı, kolayca aşılabilir. Yukarıdaki programda olduğu gibi, alt program içinden global<global değişken adı> bildirimi yapıldığında , belirtilen global değişken üzerinde, her türlü değişim ve yoketme yapılabilir. Bu değişiklikler, global program alanına da yansır. Yukarıdaki programın çıktısında, bu olay açıkça görülmektedir.

Programda, dışFonksiyon içinden tanımlanmış olan b değişkeni, global program alanı açışından yerel bir değişkendir ve buna global program alanı altından erişilemez. Bu değişken, içFonksiyon() açısından, nonLocal bir değişkendir ve değerine içFonksiyon() içinden erişilebilir ve eğer, nonlocal<lokal olmayan değişken adı> bildirimi yapılmışsa, değeri içFonksiyon() içinden değiştirilebilir. Program akışı içinde bu gerçekleşmiş ve b değişkeninin değeri, içFonksiyon() içinden değiştirilmiştir.

Programda, içFonksiyon() içinden bir s global değişkeni tanımlanmış ve değerinden, global program alanı içinde yararlanılmıştır.

Aynı şekilde, içFonksiyon() içinden bir x globsal değişkeni tanımlanmış ve değerine global kapsam alanı içinde erişebildiği görülmüştür.

Bu programın kötü tarafı global değişken kullanılmış olması, daha da kötü tarafı bu global değişkenlerden bazılarının fonksiyonlar içinden tanımlanmış olması, bazılarının da, değerlerinin yerel kapsam alanlarında değiştirilmiş olmasıdır. Bu gibi, tanımlamalar, programcının program üzerinde kontolünü kaybetmesine yol açabilir. Olanaklar ölçüsünde, bu gibi tanımlamalar ve değer değiştirmelerden kaçınılmalıdır.

llk bir iyileştirme için, programı gereksiz tanımlanmış değişkenlerden temizleyelim. Aşağıdaki program, yapılmış olan bu ilk iyileştirmeleri yansıtmaktadır.

  # Program : Ders14program3.py
  
  global_1 = 11; # global kapsam
  
  def dışFonksiyon():
  dışFonksiyon_1 = 23;
  """dışFonksiyon açısından yerel(lokal),  
içFonksiyon açısından nonLocal (yerel olmayan) kapsam,
dışFonksiyon kapsamı dışında tanımsız."""
def içFonksiyon(): global global_1; # Global değişken global_1 ya bağlandı! global_1 = 919; # Global değişkenin değeri değişti! nonlocal dışFonksiyon_1; # Yerel olmayan değişken dışFonksiyon_1 ya bağlandı! dışFonksiyon_1 = 645; # Yerel olmayan değişkenin değeri değişti! içFonksiyon(); return dışFonksiyon_1; def msg(): return('{0:20}{1:20}{2:20}'.format('Bu değişkenin değeri,',
'bir alt program içinde\n', 'değiştirilmiştir !\nYeni değer : '
)); def anaProgram(): mesaj = msg(); anaProgramDeğişken_1 = dışFonksiyon(); if not anaProgramDeğişken_1 == 23: print(mesaj, 'dışFonksiyon_1 = ', anaProgramDeğişken_1 , '\n'); if not global_1 == 11: print(mesaj, 'global_1 = ', global_1); anaProgram(); ---------Program----Sonucunun----Görüntülenmesi---------------------------- Bu değişkenin değeri,bir alt program içinde değiştirilmiştir ! Yeni değer : dışFonksiyon_1 = 645 Bu değişkenin değeri,bir alt program içinde değiştirilmiştir ! Yeni değer : global_1 = 919

Yukarıdaki program, yapısal olarak birçok değişiklikler içermektedir. Global alanda, sadece global değişkenler ve fonksiyonlar tanımlanmışlardır. Global değişkenler, program içinde kolay izlenebilmeleri için global_x şeklinde isimlendirilmişlerdir. Programda sadece bir tek global değişken bulunmaktadır.

Fonksiyonlar arasında yeni tanımlanmış bir msg () fonksiyonu bulunmaktadır. Bu fonksiyon, iç fonksiyon içinden, mesaj taşıyan bir global değişken tanımlanma gereksinimini ortadan kaldırmaktadır. Bu şekilde, büyük bir güvenlik sorunu ortadan kaldırılmıştır. Alt fonksiyonlar içinde yeni global değişkenler oluşturmak, programcının program yürüşünün kontrolünü kaybetmesi olanağını ortaya çıkaran potansiyel bir hata kaynağıdır.

Programda tüm işlevsel çalışmalar, yeni tanımlanmış bir ana program içinden yürütülmektedir. Ana program alt programları çağırmakta, geri döndürülen değerleri değerlendirmekte, verilmesi gereken çıktıları oluşturmaktadır.

Ana programın amacı, tehlikeli global değişkenlerin gereksiniminin azaltılmasıdır. Fonksiyonlardan gelen geri dönüş değerleri, artık global değil, ana fonksiyon içinde tanımlanmış yerel değişkenlere aktarılmaktadır. Bu yerek değişkenler, sadece ana fonksiyon içinde tanımlı olup, değerleri başka alt fonksiyonlar içinde değiştirilememektedir. Bu da büyük bir güvenlik avantajı sağlamaktadır.

Alt programlarda tanımlanma zorunluluğu olan yerel ve yerek olmayan değişkenler, dikkat çekecek şekilde isimlendirilerek değerlerinin iç fonksiyonlara değişmesi durumunda, olayın gözden kaçabilmesinin engellenmesi sağlanmaya çalışılmıştır.

Görüldüğü gibi, hem global hem de yerel olmayan değişkenler, potansiyel hata kaynakları olup, kullanılmaları tamamen ortadan kaldırılabilme olanağı bulunmasa bile, hiç değilse en aza indirilmelidir.

Global ve yerel olmayan değişkenler, program yürüyüşü içinde, yeniden çağrılmamaları durumunda, Python çöp toplayıcısı tarafından ortadan kaldırılırlar. Yine de, aşırı önlem alma yanlısı programcılar, bu değişkenlerin kullanım gereksinmeleri ortadan kalkınca,

    del <değişkenAdı>

şeklinde programdan uzaklaştırabilirler.

Bir programın global değişken gerektirmeyen sürümleri daima bulunabilir. Bu sürümler biraz daha kompakt bir kodlama gerektirebilirler. Örnek olarak, aşağıdaki programda, anaProgram() içindeki iletişim amaçlı yerel değişken, anaProgramDeğişken_1 kullanımı yerine, fonksiyondan doğrudan bilgi aktarımı yöntemi kullanılmıştır.

  # Program : Ders14program4.py
  
  global_1 = 11 # global kapsam
  
  def dışFonksiyon():
  dışFonksiyon_1 = 23
"""dışFonksiyon açısından yerel(lokal),
içFonksiyon açısından nonLocal (yerel olmayan) kapsam,
dışFonksiyon kapsamı dışında tanımsız."""
def içFonksiyon(): global global_1 # Global değişken global_1 ya bağlandı! global_1 = 919 # Global değişkenin değeri değişti! nonlocal dışFonksiyon_1 # Yerel olmayan değişken dışFonksiyon_1 ya bağlandı! dışFonksiyon_1 = 645 # Yerel olmayan değişkenin değeri değişti! içFonksiyon() return dışFonksiyon_1

def msg(): return('{0:20}{1:20}{2:20}'.format('Bu değişkenin değeri,',
'bir alt program içinde\n', 'değiştirilmiştir !\nYeni değer : '
)) def anaProgram(): mesaj = msg() if not dışFonksiyon() == 23: print(mesaj, 'dışFonksiyon_1 = ', dışFonksiyon() , '\n') if not global_1 == 11: print(mesaj, 'global_1 = ', global_1) anaProgram(); ---------Program----Sonucunun----Görüntülenmesi---------------------------- Bu değişkenin değeri,bir alt program içinde değiştirilmiştir ! Yeni değer : dışFonksiyon_1 = 645 Bu değişkenin değeri,bir alt program içinde değiştirilmiştir ! Yeni değer : global_1 = 919

Yukarıdaki programda görüldğü gibi, ana program içinde iletişim amaçlı bir yerel değişken tanımı yerine, fonksiyondan doğrudan bilgi aktarımı yöntemi uygulanmış ve bunun sonucunda biraz daha zor okunan bir kodlama oluşmuştur.

Python programlama dilinde, bildirim sonunda noktalı virgül kullanımı gerekli değildir. Bu nedenle, yukarıdaki programda noktalı virgül kullanılmamıştır.

Python programları yukarıdan aşağıya doğru derlenirler, ve bir program öğesini çağırmadan önce, bunun tanımlanmış olması gerekir. Bu nedenle ana program, tüm fonksiyon ve global tanımların tamamlanmalarından sonra, global kapsam alanının en altına konulmuştur. Yine aynı şekilde, dışFonksiyon() içinde, içFonksiyon() önce tanımlanmış, sonra çağrılmıştır.

Python programlama dilindeki kolaylıklardan biri, fonksiyon argümanlarına isimleri ile değer verilebilmesidir. Argümanlara isimleri ile değer verildiğinde, argümanların tanım sıralarının gözetilmesi gerekmez. Aşağıdaki küçük bir örnek bu tür bir fonksiyon çağrısını açıklamaktadır.

  # Ders14program5.py
  
  def görüntüle(a , b):
   print(' a =', a , ' b =' , b);
  
  görüntüle(b = 88 , a = 77);
  
    	
    	---------Program----Sonucunun----Görüntülenmesi-----------------------
   a = 77  b = 88    
      
    

Argümanların isimle belirtilmesi, özellikle çok sayıda argümanı olan fonksiyonlarda, çok yararlı bir özellik olarak kabul edilmektedir.

Python fonksiyonları değişken sayıda argüman alabilecek şekilde tanımlanabilirler. Aslında, bu özellik Java ve JavaScript gibi modern bilgisayar dillerinde de sağlanmıştır. Değişken sayıda argüman ile fonksiyonu çağırabilme özelliği, fonksiyonun değişen koşullara uyumunu sağlayan ve bu şekilde, büyük bir esneklik veren bir özelliktir. Bir arkadaş grubunuz olduğunu düşünün. Bu arkadaşlara bir kutlama günü davetiyesi göndereceksiniz, fakat bunlardan bazıları her zaman davete gelebilecek durumda olmayabilir. Bunun için bir genel davetiye fonksiyonu yazılır ve değişken sayıda argüman alabilmesi sağlanır. Bundan sonra bu fonksiyonu her zaman kullanabilir ve sadece elde olan arkadaşlarınıza çağrı yapmasını sağlayabilirsiniz. Aşağıdaki program bu konuda bir örnek olararak düzenlenmiştir.

  # Ders14program6.py
      
  def arkadaşListesi(*arkadaş):
  
  maxVeri = len(arkadaş);
  
  i  =  0;
  
  while i < maxVeri:
  
  print('Sayın ,' , arkadaş[i] , '\n \
16 kasım saat 13.00 den itibaren başlayacak olan \n \
mangal partimize, lütfen katılmanızı rica ederim. \n \
Saygılar, \n \
Bedri Doğan Emir \n'
); i = i + 1; def main : arkadaşListesi(
'Hasan Elbasan', 'Ahmet Kahraman', 'Asena Kündeci', 'Tomris Başkesen'); if __name__ == '__main__': main(); ---------Program----Sonucunun----Görüntülenmesi-----------------------
Sayın , Hasan Elbasan
16 kasım saat 13.00 den itibaren başlayacak olan
mangal partimize, lütfen katılmanızı rica ederim.
Saygılar,
Bedri Doğan Emir

Sayın , Ahmet Kahraman
16 kasım saat 13.00 den itibaren başlayacak olan
mangal partimize, lütfen katılmanızı rica ederim.
Saygılar,
Bedri Doğan Emir

Sayın , Asena Kündeci
16 kasım saat 13.00 den itibaren başlayacak olan
mangal partimize, lütfen katılmanızı rica ederim.
Saygılar,
Bedri Doğan Emir

Sayın , Tomris Başkesen
16 kasım saat 13.00 den itibaren başlayacak olan
mangal partimize, lütfen katılmanızı rica ederim.
Saygılar,
Bedri Doğan Emir

Yukarıdaki programda, print() fonksiyonu içindeki '\n \ şeklindeki bildirimin ilk '\n' sözel verinin görüntlenmesinin yeni satırdan devam edilmesini bildirien kaçış karakteri, ikinci '\' (ters şlaş) karakterinin ise, program yazımında, uzun sözel verilerin aynı ekranda kalmasını sağlamak için yazılımda alt satıra geçildiğini belirten bir ifade şeklidir.

Yine yukarıdaki programda, argümanlar, bir sözlük içine alınmıştır ve burada argümanlar arasında her iterasyon bir argüman değerine karşı gelmektedir. Çok güzel, ve argüman sayısı önceden belirli olmayan durumlarda çok işe yarayan bir özelliktir.

Her şey güzel ama, ya parti tarihini veya parti cinsini önceden belirtmesek ve daetiyemiz, değişik tarihlerde, değişik türde partilerimiz için, değişken sayıdaki davetliler için geçerli olacak şekilde düzenlense daha da iyi olabilir. Bu olanak Python programlama dilinde sağlanmıştır. Bunun için, tarih ve parti türünü sabit argümanlar, davetlileri ise, değişken sayıda argümanlar olarak belirterek fonksiyon tanımını gerçekleştirebiliriz. Aşağıdaki program bu yöntemi uyglamaktadır.

# Ders14program7.py    

def arkadaşListesi(tarih = '2 Aralık 2014', parti = 'Mangal', *arkadaş): maxVeri = len(arkadaş); i = 0; while i maxVeri: print('\n',
' Sayın \n ', arkadaş[i] , ', \n', ''' {0:25} den itibaren başlayacak olan
{1:3} partimize, lütfen katılmanızı rica ederim.
Saygılarımla,
Bedri Doğan Emir '''
.format(tarih, parti)); i = i + 1; def main(): arkadaşListesi('2 Ocak 2015 günü, saat 15.00', 'Çay', 'Tülin Özer', 'Güler Karbeyaz', 'Fortune Behar', 'Andonis Karaoğlu'); if __name__ == '__main__': main(); ---------Program----Sonucunun----Görüntülenmesi-----------------------


Sayın
Tülin Özer ,
2 Ocak 2015 günü, saat 15.00 den itibaren başlayacak olan
Çay partimize, lütfen katılmanızı rica ederim.
Saygılarımla,
Bedri Doğan Emir

Sayın
Güler Karbeyaz ,
2 Ocak 2015 günü, saat 15.00 den itibaren başlayacak olan
Çay partimize, lütfen katılmanızı rica ederim.
Saygılarımla,
Bedri Doğan Emir

Sayın
Fortune Behar ,
2 Ocak 2015 günü, saat 15.00 den itibaren başlayacak olan
Çay partimize, lütfen katılmanızı rica ederim.
Saygılarımla,
Bedri Doğan Emir

Sayın
Andonis Karaoğlu ,
2 Ocak 2015 günü, saat 15.00 den itibaren başlayacak olan
Çay partimize, lütfen katılmanızı rica ederim.
Saygılarımla,
Bedri Doğan Emir

Bir önceki programdaki açıklamalara, bu program için eklenecek yeni bir konu bulunmamaktadır. Bu yeni programda uygulanan yöntem, bir öncekine göre, çok daha fazla esneklik sunuyor. Sonuçların biçimlendirilmesi, bu tür mesajların kolayca düzenlenebildiğini ortaya koymaktadır.