Fonksiyonlar¶
Şimdi şöyle bir düşünün: Diyelim ki çalıştığınız işyerinde her gün bir yerlere dilekçe gönderiyorsunuz. Aslında farklı yerlere gönderdiğiniz bu dilekçeler temel olarak aynı içeriğe sahip. Yani mesela dilekçeyi Mehmet Bey’e göndereceğiniz zaman yazıya Mehmet Bey’in adını; Ahmet Bey’e göndereceğiniz zaman ise Ahmet Bey’in adını yazıyorsunuz. Ayrıca tabii dilekçe üzerindeki tarih bilgilerini de güne göre düzenliyorsunuz. Mantıklı bir insan, yukarıdaki gibi bir durumda elinde bir dilekçe taslağı bulundurur ve sadece değiştirmesi gereken kısımları değiştirip dilekçeyi hazır hale getirir. Her defasında aynı bilgileri en baştan yazmaz. Dilerseniz anlattığımız bu durumu Python programlama dili ile temsil etmeye çalışalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print """Sayın Mehmet Bey,
19.12.2009 tariginde yaptığımız başvurunun sonuçlandırılması
hususunda yardımlarınızı rica ederiz.
Saygılarımızla,
Orçun Kunek"""
Bu dilekçe Mehmet Bey’e gidiyor. İsterseniz bir tane de Ahmet Bey’e yazalım...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
print """Sayın Ahmet Bey,
15.01.2010 tariginde yaptığımız başvurunun sonuçlandırılması
hususunda yardımlarınızı rica ederiz.
Saygılarımızla,
Orçun Kunek"""
Burada dikkat ederseniz iki dilekçenin metin içeriği aslında aynı. Sadece bir-iki yer değişiyor. Bu kodları bu şekilde yazmak oldukça verimsiz bir yoldur. Çünkü bu sistem hem programcıya çok vakit kaybettirir, hem fazlasıyla kopyala-yapıştır işlemi gerektirir, hem de bu kodların bakımını yapmak çok zordur. Eğer dilekçe metni üzerinde bir değişiklik yapmak isterseniz program içindeki ilgili kodları tek tek bulup düzeltmeniz gerekir. Yani mesela yukarıdaki iki dilekçenin aynı program içinde olduğunu varsayarsak, dilekçe metnindeki bir hatayı düzeltmek istediğimizde aynı düzeltmeyi birkaç farklı yerde yapmamız gerekir. Örneğin yukarıdaki dilekçe metninde bir yazım hatası var. İlk satırda “tarihinde” yazacağımıza “tariginde” yazmışız... Tabii biz Mehmet Bey’e yazdığımız dilekçenin metnini Ahmet Bey’e yazacağımız dilekçeyi hazırlarken kopyala-yapıştır yaptığımız için aynı hata Mehmet Bey’e gidecek dilekçede de var. Şimdi biz bu yazım hatasını düzeltmek istediğimizde, bütün dilekçe metinlerini tek tek gözden geçirmemiz gerekecektir. Hele bir de dilekçe sayısı çok fazlaysa bu işlemin ne kadar zor olacağını bir düşünün. Tabii bu basit durum için, her metin düzenleyicide bulunan “bul-değiştir” özelliğini kullanabiliriz. Ama işler her zaman bu kadar kolay olmayabilir. Bu bakım ve taslaklama işini kolaylaştıracak bir çözüm olsa ve bizi aynı şeyleri tekrar tekrar yazmaktan kurtarsa ne kadar güzel olurdu, değil mi? İşte Python buna benzer durumlar için bize “fonksiyon” denen bir araç sunar. Biz de bu bölümde bu faydalı aracı nasıl kullanacağımızı öğrenecek ve bu aracı olabildiğince ayrıntılı bir şekilde incelemeye çalışacağız.
Fonksiyonları Tanımlamak¶
Python’da fonksiyonları kullanabilmek için öncelikle fonksiyonları tanımlamamız gerekiyor. Fonksiyon tanımlamak için def adlı bir parçacıktan yararlanacağız. Python’da fonksiyonları şöyle tanımlıyoruz:
def fonksiyon_adi():
...
Gördüğünüz gibi, önce def parçacığını, ardından da fonksiyonumuzun adını yazıyoruz. Fonksiyon adı olarak istediğiniz her şeyi yazabilirsiniz. Ancak fonksiyon adı belirlerken, fonksiyonun ne işe yaradığını anlatan kısa bir isim belirlemeniz hem sizin hem de kodlarınızı okuyan kişilerin işini bir hayli kolaylaştıracaktır. Yalnız fonksiyon adlarında Türkçe karakter kullanmamanız gerekiyor. Ayrıca fonksiyonları tanımlarken en sona parantez ve iki nokta üst üste işaretlerini de koymayı unutmuyoruz.
Böylece ilk fonksiyonumuzu tanımlamış olduk. Ama henüz işimiz bitmedi. Bu fonksiyonun bir işe yarayabilmesi için bunun altını doldurmamız gerekiyor. Fonksiyon tanımının iki nokta üst üste işareti ile bitmesinden, sonraki satırın girintili olması gerektiğini tahmin etmişsinizdir. Gelin isterseniz biz bu fonksiyonun altını çok basit bir şekilde dolduralım:
def fonksiyon_adi():
print "merhaba fonksiyon!"
Böylece eksiksiz bir fonksiyon tanımlamış olduk. Burada dikkat etmemiz gereken en önemli şey, def fonksiyon_adi(): satırından sonra gelen kısmın girintili yazılmasıdır.
Şimdi isterseniz bu fonksiyonu nasıl kullanabileceğimizi görelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonksiyon_adi():
print "merhaba fonksiyon!"
Bu kodları bir metin düzenleyiciye kaydedip çalıştırdığımızda hiç bir çıktı elde edemeyiz. Çünkü biz burada fonksiyonumuzu sadece tanımlamakla yetindik. Henüz bu fonksiyonun işletilmesini sağlayacak kodu yazmadık. Şimdi bu fonksiyonun hayat kazanmasını sağlayacak kodları girebiliriz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonksiyon_adi():
print "merhaba fonksiyon!"
fonksiyon_adi()
Burada fonksiyonun çalışmasını sağlayan şey, en son satırdaki fonksiyon_adi() kodudur. Bu satırı ekleyerek, daha önce tanımladığımız fonksiyonu çağırmış oluyoruz. Bu satıra teknik olarak fonksiyon çağrısı (function call) adı verilir.
Yukarıdaki kodları çalıştırdığımızda ekrana merhaba fonksiyon! satırının yazdırıldığını göreceğiz.
Tebrikler! Böylece ilk eksiksiz fonksiyonunuzu hem tanımlamış, hem de çağırmış oldunuz. Dilerseniz, bu konunun en başında verdiğimiz dilekçe örneğini de bir fonksiyon haline getirelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def dilekce_gonder():
print """\
Sayın Mehmet Bey,
19.12.2009 tarihinde yaptığımız başvurunun sonuçlandırılması
hususunda yardımlarınızı rica ederiz.
Saygılarımızla,
Orçun Kunek"""
dilekce_gonder()
Elbette bu örnek Python’daki fonksiyonların bütün yeteneklerini ortaya koymaktan aciz. Üstelik bu fonksiyon, en başta bahsettiğimiz sorunları da çözemiyor henüz. Ama ne yapalım... Şu ana kadar öğrendiklerimiz ancak bu kadarını yapmamıza müsaade ediyor. Biraz sonra öğreneceklerimiz sayesinde fonksiyonlarla çok daha faydalı ve manalı işler yapabileceğiz.
Yeni bir bölüme geçmeden önce isterseniz fonksiyonlarla ilgili olarak buraya kadar öğrendiğimiz kısmı biraz irdeleyelim:
- Python’da fonksiyonlar bizi aynı şeyleri tekrar tekrar yazma zahmetinden kurtarır.
- Fonksiyonlar bir bakıma bir taslaklama sistemi gibidir. Biraz sonra vereceğimiz örneklerde bu durumu daha net olarak göreceğiz.
- Python’da fonksiyonları kullanabilmek için öncelikle fonksiyonu tanımlamamız gerekir. Bir fonksiyonu tanımlamak için def adlı parçacıktan yararlanıyoruz.
- Python’da bir fonksiyon tanımı şöyle bir yapıya sahiptir:
def fonksiyon_adi():
...
- Fonksiyon adlarını belirlerken Türkçe karakter kullanmıyoruz. Fonksiyonlarımıza vereceğimiz adların olabildiğince betimleyici olması herkesin hayrınadır.
- Elbette bir fonksiyonun işlevli olabilmesi için sadece tanımlanması yetmez. Ayrıca tanımladığımız fonksiyonun bir de gövdesinin olması gerekir. Fonksiyon gövdesini girintili olarak yazıyoruz. Dolayısıyla Python’da bir fonksiyon temel olarak iki kısımdan oluşur. İlk kısım fonksiyonun tanımlandığı başlık kısmı; ikinci kısım ise fonksiyonun içeriğini oluşturan gövde kısmıdır. Başlık ve gövde dışında kalan her şey fonksiyonun da dışındadır.
- Bir fonksiyon, gövdedeki girintili kısmın bittiği yerde biter. Örneğin şu bir fonksiyondur:
def selamla():
print "merhaba!"
print "nasılsın?"
Bu fonksiyon def selamla(): satırıyla başlar, print "nasılsın?" satırıyla biter.
- Fonksiyonların işlevli olabilmesi için bu fonksiyonlar tanımlandıktan sonra çağrılmalıdır. Örneğin yukarıdaki fonksiyonu şöyle çağırıyoruz:
def selamla():
print "merhaba!"
print "nasılsın?"
selamla()
Dediğimiz gibi, bu fonksiyon def selamla(): satırıyla başlar, print "nasılsın?" satırıyla biter. Fonksiyon çağrısı dediğimiz selamla() satırı bu fonksiyonun dışındadır. Çünkü bu satır selamla() fonksiyonunun gövdesini oluşturan girintili kısmın dışında yer alıyor.
Eğer bu söylediklerimiz size biraz kafa karıştırıcı gelmişse, hiç endişe etmenize gerek yok. Tam olarak ne demek istediğimizi biraz sonra gayet net bir şekilde anlamanızı sağlayacak örnekler vereceğiz.
Dilerseniz bu bölümü kapatmadan önce fonksiyonlarla ilgili birkaç basit örnek daha yaparak bu konuya ısınmanızı sağlayalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def tek():
print "Girdiğiniz sayı bir tek sayıdır!"
def cift():
print "Girdiğiniz sayı bir çift sayıdır!"
sayi = raw_input("Lütfen bir sayı giriniz: ")
if int(sayi) % 2 == 0:
cift()
else:
tek()
Burada tek() ve cift() adlı iki fonksiyon tanımladık. tek() adlı fonksiyonun görevi ekrana Girdiğiniz sayı bir tek sayıdır! çıktısı; cift() adlı fonksiyonun görevi ise Girdiğiniz sayı bir çift sayıdır! çıktısı vermek.
Daha sonra Python’un raw_input() fonksiyonunu kullanarak kullanıcıdan bir sayı girmesini istiyoruz. Ardından da kullanıcı tarafından girilen bu sayının tek mi yoksa çift mi olduğunu denetliyoruz. Eğer sayı 2’ye tam olarak bölünüyorsa çifttir. Aksi halde bu sayı tektir.
Burada cift() ve tek() adlı fonksiyonları nasıl çağırdığımıza dikkat edin. Eğer kullanıcının girdiği sayı 2’ye tam olarak bölünüyorsa, yani bu sayı çiftse, daha önce tanımladığımız cift() adlı fonksiyon devreye girecektir. Yok, eğer kullanıcının verdiği sayı 2’ye tam olarak bölünmüyorsa o zaman da tek() adlı fonksiyon devreye girer.
Bu kodlarda özellikle fonksiyonların nerede başlayıp nerede bittiğine dikkat edin. Daha önce de dediğimiz gibi, bir fonksiyon def parçacığıyla başlar, gövdesindeki girintili alanın sonuna kadar devam eder. Girintili alanın dışında kalan bütün kodlar o fonksiyonun dışındadır. Mesela yukarıdaki örnekte tek() ve cift() birbirinden bağımsız iki fonksiyondur. Bu fonksiyonlardan sonra gelen sayı değişkeni de fonksiyon alanının dışında yer alır.
Fonksiyonlarda Parametre Kullanımı¶
Yukarıdaki örneklerde gördüğünüz gibi, bir fonksiyon tanımlarken, fonksiyon adını belirledikten sonra bir parantez işareti kullanıyoruz. Bu parantez işaretleri, örneklerde de gördüğümüz gibi hiçbir bilgi içermeyebilir. Yani bu parantezler boş olabilir. Ancak yapacağımız işin niteliğine göre bu parantezlerin içine birtakım bilgiler yerleştirmemiz gerekebilir. İşte bu bilgilere parametre adı verilir. Zaten Python fonksiyonları da asıl gücünü bu parametrelerden alır. Şimdi şöyle bir örnek verdiğimizi düşünelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def selamla():
print "merhaba, benim adım istihza!"
selamla()
Burada fonksiyonumuzu tanımladıktan sonra en sondaki selamla() satırı yardımıyla fonksiyonumuzu çağırdık. Yani tanımladığımız fonksiyona hayat öpücüğü verdik.
Ancak yukarıda tanımladığımız fonksiyon oldukça kısıtlı bir kullanım alanına sahiptir. Bu fonksiyon ekrana yalnızca merhaba, benim adım istihza! çıktısını verebilir. Eğer fonksiyonların yapabildiği şey bundan ibaret olsaydı, emin olun fonksiyonlar hiçbir işimize yaramazdı. Ama şimdi öğreneceğimiz parametre kavramı sayesinde fonksiyonlarımıza takla atmayı öğreteceğiz. Gelin isterseniz çok basit bir örnekle başlayalım:
def selamla(isim):
print "merhaba, benim adım %s!" %isim
Belki fark ettiniz, belki de fark etmediniz, ama burada aslında çok önemli bir şey yaptık. Fonksiyonumuza bir parametre verdik! Şimdiye kadar tanımladığımız fonksiyonlarda, fonksiyon tanımı hep boş bir parantezden oluşuyordu. Ancak bu defa parantezimizin içinde bir değişken adı görüyoruz. Bu değişkenin adı isim. Fonksiyonlar söz konusu olduğunda, parantez içindeki bu değişkenlere parametre adı verilir. Fonksiyonumuzu tanımlarken bir parametre belirttikten sonra bu parametreyi fonksiyonun gövdesinde de kullandık. İsterseniz şimdi tanımladığımız bu fonksiyonun bir işe yarayabilmesi için fonksiyonumuzu çağıralım:
selamla("istihza")
Kodları bir arada görelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def selamla(isim):
print "merhaba, benim adım %s!" %isim
selamla("istihza")
Bu kodları çalıştırdığımızda şöyle bir çıktı alırız:
merhaba, benim adım istihza!
Burada selamla() adlı fonksiyonu istihza argümanı ile birlikte çağırdık. Böylece çıktıda istihza değerini aldık. Burada terminolojiyle ilgili ufak bir not düşelim: Fonksiyonlar tanımlanırken parantez içinde belirtilen değerlere “parametre” adı verilir. Aynı fonksiyon çağrılırken parantez içinde belirtilen değerlere ise “argüman” adı verilir. Ama her iki durum için de “parametre” adının kullanıldığını da görebilirsiniz bazı yerlerde... Neyse... Biz bu terminoloji işini bir kenara bırakıp yolumuza devam edelim.
Eğer selamla() adlı fonksiyonu farklı bir argüman ile çağırırsak elbette alacağımız çıktı da farklı olacaktır:
selamla("Ahmet Efendi")
Bu defa çıktımız şöyle:
merhaba, benim adım Ahmet Efendi!
Burada önemli olan nokta, selamla() fonksiyonunun bir adet parametreye sahip olmasıdır. Dolayısıyla bu fonksiyonu argümansız olarak veya birden fazla argümanla çağıramayız. Yani fonksiyonu şu şekillerde çağırmak hata almamıza yol açacaktır:
selamla("Ahmet", "Mehmet")
veya:
selamla()
Sanırım bu örnekler fonksiyonlardaki parametre kavramının ne olduğunu net bir biçimde ortaya koyuyor. Daha sonraki bölümlerde bu parametre kavramından bolca yararlanacağız. İlerde göreceğimiz örnekler ne kadar karmaşık olursa olsun, işin temeli aynen yukarıda anlattığımız gibidir. Eğer bu temeli iyi kavrarsanız başka yerlerde göreceğiniz daha karmaşık örnekleri anlamakta zorlanmazsınız.
Dilerseniz bu anlattıklarımızla ilgili ufak bir örnek daha yapıp başka bir konuya geçelim...
Python’da, verilen sayıları toplayan sum() adlı bir fonksiyon olduğunu önceki derslerimizde öğrenmiştik. Bu fonksiyonu şöyle kullanıyorduk:
>>> sayilar = [45, 90, 43]
>>> sum(sayilar)
178
sum() fonksiyonu, kendisine argüman olarak verilen bir sayı listesinin öğelerini birbiriyle toplayıp sonucu bize bildiriyor. Ancak Python’da bu sum() fonksiyonuna benzer bir şekilde bir sayı listesini alıp, öğelerini birbiriyle çarpan hazır bir fonksiyon bulunmuyor. Python bize bu işlem için herhangi bir hazır fonksiyon sunmadığından, böyle bir durumda kendi yöntemimizi kendimiz icat etmek zorundayız. O halde hemen başlayalım. Diyelim ki elimizde şöyle bir sayı listesi var:
>>> sayilar = [45, 90, 43]
Soru şu: Acaba bu listedeki sayıları birbiriyle nasıl çarparız? Bunu yapmanın en kolay yolu, listedeki bütün sayıları 1’le çarpıp, bütün değerleri tek bir değişken içinde toplamaktır. Yani öncelikle değeri 1 olan bir değişken belirlememiz gerekiyor:
>>> a = 1
Daha sonra listedeki bütün sayıları a değişkeninin değeriyle çarpıp, bu değeri yine a değişkenine atayacağız:
>>> for i in sayilar:
... a = a * i
Yukarıdaki kodları şöyle de yazabileceğimizi biliyorsunuz:
>>> for i in sayilar:
... a *= i
Böylece listedeki bütün sayıların çarpımını gösteren değer a değişkenine atanmış oldu. İsterseniz bu a değişkeninin değerini yazdırıp sonucu kendi gözlerinizle görebilirsiniz:
>>> print a
174150
Gördüğünüz gibi, listedeki bütün sayıların çarpımı a değişkeninde tutuluyor.
Kodları topluca görelim:
>>> sayilar = [45, 90, 43]
>>> a = 1
>>> for i in sayilar:
... a *= i
...
>>> print a
174150
Şimdi şöyle bir düşünün: Diyelim ki bir program yazıyorsunuz ve bu programın değişik yerlerinde, bir liste içindeki sayıları birbiriyle çarpmanız gerekiyor. Bunun için şöyle bir yol takip edebilirsiniz:
- Önce bir sayı listesi tanımlarsınız,
- Daha sonra, değeri 1 olan bir değişken tanımlarsınız,
- Son olarak da listedeki bütün sayıları bu değişkenin değeriyle çarpıp, elde ettiğiniz değeri tekrar bu değişkene atarsınız,
- Program içinde, gereken her yerde bu işlemleri tekrar edersiniz...
Bu yöntem, sizi aynı şeyleri sürekli tekrar etmek zorunda bıraktığı için oldukça verimsiz bir yoldur. İşte Python’daki fonksiyonlar böyle bir durumda hemen devreye girer. Mantıklı bir programcı, yukarıdaki gibi her defasında tekerleği yeniden icat etmek yerine, tekerleği bir kez icat eder, sonra gereken yerlerde icat ettiği bu tekerleği kullanır. Biz de yukarıdaki işlemleri içeren bir fonksiyonu tek bir kez tanımlayacağız ve program içinde gereken yerlerde bu fonksiyonu çağıracağız. Şimdi gelin yukarıdaki işlemleri içeren fonksiyonumuzu tanımlayalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def carp(liste):
a = 1
for i in liste:
a *= i
print a
Böylece taslağımızı oluşturmuş olduk. Artık bu fonksiyonu kullanarak istediğimiz bir sayı grubunu birbiriyle rahatlıkla çarpabiliriz. Bunun için yapmamız gereken tek şey carp() adlı fonksiyonu çağırmak:
carp([3, 5, 7])
Burada dikkat ederseniz, carp() fonksiyonuna argüman olarak verdiğimiz sayıları bir liste içine aldık. Çünkü carp() fonksiyonu tek bir parametre alıyor. Eğer bu fonksiyonu şu şekilde çağırırsanız hata alırsınız:
carp(3, 5, 7)
Çünkü burada carp() fonksiyonuna birden fazla argüman verdik. Halbuki fonksiyonumuz sadece tek bir argüman alıyor. Elbette dilerseniz önce bir sayı listesi tanımlayabilir, ardından da bu listeyi fonksiyona argüman olarak verebilirsiniz:
sayilar = [3, 5, 7]
carp(sayilar)
Şimdi kodları topluca görelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def carp(liste):
a = 1
for i in liste:
a = a * i
print a
sayilar = [3, 5, 7]
carp(sayilar)
Bu kodları çalıştırdığınızda 105 sonucunu alırsınız.
Bu arada, yukarıdaki kodlarda carp() fonksiyonuna ait liste adlı parametrenin yalnızca temsili bir isimlendirme olduğuna dikkat edin. Program içinde daha sonra fonksiyonu çağırırken argüman olarak kullanacağınız değerin “liste” adını taşıma zorunluluğu yoktur. Mesela bizim örneğimizde carp() fonksiyonunu “sayilar” adlı bir liste ile çağırdık... Yani yukarıdaki fonksiyonu şöyle de yazabilirdik:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def carp(osman):
a = 1
for i in osman:
a = a * i
print a
Daha sonra da yine bu fonksiyonu şu şekilde çağırabiliriz:
sayılar = [3, 5, 7]
carp(sayilar)
Elbette fonksiyon içinde belirttiğiniz parametrelerin anlamlı bir ada sahip olması herkes için en doğrusudur.
Fonksiyonların işimizi ne kadar kolaylaştırdığını görüyorsunuz. Yapmak istediğimiz işlemleri bir fonksiyon olarak tanımlıyoruz ve gerektiği yerde bu fonksiyonu çağırarak işimizi hallediyoruz. Eğer işlemlerde bir değişiklik yapmak gerekirse, tanımladığımız fonksiyonu yeniden düzenlememiz yeterli olacaktır. Eğer fonksiyonlar olmasaydı, fonksiyon içinde tek bir kez tanımladığımız işlemi programın farklı yerlerinde defalarca tekrar etmemiz gerekecekti. Üstelik işlemlerde bir değişiklik yapmak istediğimizde de, bütün programı baştan sona tarayıp değişiklikleri tek tek elle uygulamak zorunda kalacaktık.
Dilerseniz en başta verdiğimiz dilekçe örneğine tekrar dönelim ve o durumu fonksiyonlara uyarlayalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def dilekce_gonder(kime, tarih, kimden):
print """\
Sayın %s,
%s tarihinde yaptığımız başvurunun sonuçlandırılması
hususunda yardımlarınızı rica ederiz.
Saygılarımızla,
%s""" %(kime, tarih, kimden)
dilekce_gonder("Mehmet Bey", "19.12.2009", "Orçun Kunek")
Gördüğünüz gibi, yukarıdaki fonksiyon işimizi bir hayli kolaylaştırıyor. Burada fonksiyonumuzu sadece bir kez oluşturuyoruz. Ardından dilekçeyi kime göndereceksek, uygun bilgileri kullanarak yeni bir fonksiyon çağrısı yapabiliriz. Mesela dilekçeyi Ahmet Bey’e göndereceksek şöyle bir satır yazmamız yeterli olacaktır:
dilekce_gonder("Ahmet Bey", "21.01.2010", "Erdener Topçu")
Ayrıca dilekçe metninde bir değişiklik yapmak istediğimizde sadece fonksiyon gövdesini düzenlememiz yeterli olacaktır.
İsimli ve Sıralı Argümanlar¶
Bir önceki bölümde fonksiyon parametrelerini nasıl kullanacağımızı öğrendik. Python’da fonksiyonlara istediğiniz sayıda parametre verebilirsiniz. Mesela şöyle bir fonksiyon tanımlayabilirsiniz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "Bağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
kayit_ekle("Orçun", "Kunek",
"Adana", "Şarkıcı",
"0322 123 45 67", "Baraj Yolu")
Yine burada, kodlarımızın çirkin bir görüntü oluşturmaması için öğeleri nasıl alt satıra geçirdiğimize dikkat edin. Eğer Python kodlarına duyarlı bir metin düzenleyici kullanıyorsanız (mesela IDLE) virgül işaretlerinden sonra ENTER tuşuna bastığınızda düzgün girinti yapısı otomatik olarak oluşturulacaktır.
Bu kodlarda öncelikle kayit_ekle() adlı bir fonksiyon tanımladık. Bu fonksiyon toplam altı adet parametre alıyor. Bunlar; isim, soyisim, sehir, meslek, tel ve adres.
Tanımladığımız bu fonksiyonun gövdesinde ilk olarak kayit adlı bir sözlük oluşturduk. Bu sözlük, ekleyeceğimiz bağlantıya dair bilgileri tutacak. Daha sonra, oluşturduğumuz bu sözlüğe öğe ekliyoruz. Buna göre, fonksiyon parametrelerinden olan isim ve soyisim; kayit adlı sözlükteki “anahtar” kısmını oluşturacak. sehir, meslek, tel ve adres değerleri ise kayit adlı sözlükteki “değer” kısmını meydana getirecek.
Sözlüğü oluşturduktan sonra ekrana Bağlantı bilgileri kayıtlara eklendi! biçiminde bir mesaj yazdırıyoruz. Daha sonra da kayıt adlı sözlüğün öğelerini belli bir düzen çerçevesinde ekrana yazdırıyoruz.
Bu işlemi nasıl yaptığımıza dikkat edin. Python sözlüklerinde items() adlı bir metot olduğunu sözlükler konusunu işlerken öğrenmiştik. Bu metot yardımıyla bir sözlük içinde bulunan bütün anahtar ve değer çiftlerini elde edebiliyorduk. Dilerseniz buna bir örnek vererek bu metodu tekrar hatırlayalım.
Diyelim ki elimizde şöyle bir sözlük var:
>>> sozluk = {"programlama dili": "Python",
... "metin duzenleyici": "Kwrite"}
Şimdi items() metodunu bu sözlük üzerine uygulayalım:
>>> print sozluk.items()
[('programlama dili', 'Python'),
('metin duzenleyici', 'Kwrite')]
Gördüğünüz gibi, sozluk adlı sözlüğe ait bütün anahtar ve değerler bir liste içinde demetler halinde toplandı. Şimdi şöyle bir şey yazalım:
>>> for k, v in sozluk.items():
... print k, v
Buradan şöyle bir çıktı alırız:
programlama dili Python
metin düzenleyici Kwrite
Bu şekilde bir çıktı elde ettikten sonra artık bu çıktıyı istediğimiz şekilde biçimlendirebileceğimizi biliyoruz.
items() metodunu hatırlattığımıza göre biz tekrar kayit_ekle() fonksiyonumuzu incelemeye devam edebiliriz. Biraz önce anlattığımız gibi, kayit_ekle() fonksiyonu içindeki for k, v in kayit.items(): satırında k değişkeni kayit adlı sözlükteki anahtarları, v değişkeni ise aynı sözlükteki değerleri temsil ediyor. Böylece sözlükteki anahtar ve değer çiftlerini birbirinden ayırmış olduk.
Bu işlemi yaptıktan sonra, öncelikle k değişkenini ekrana yazdırıyoruz. Yani kayit adlı sözlükteki anahtar kısmını almış oluyoruz. Bu kısım, fonksiyondaki isim ve soyisim parametrelerinin değerini gösteriyor... print "-"*len(k) satırı ise, bir önceki satırda ekrana yazdırdığımız isim ve soyismin altına, isim ve soyisim değerlerinin uzunluğu kadar çizgi çekmemizi sağlıyor. Böylece isim ve soyismi, fonksiyondaki öteki bilgilerden görsel olarak ayırmış oluyoruz.
En son olarak da kayit adlı sözlüğün “değer” kısmındaki öğeleri tek tek ekrana yazdırıyoruz.
Fonksiyonumuzu başarıyla tanımladıktan sonra sıra geldi bu fonksiyonu çağırmaya...
Fonksiyonumuzu sırasıyla, Orçun, Kunek, Adana, Şarkıcı, 0322 123 45 67 ve Baraj Yolu argümanlarıyla birlikte çağırıyoruz. Böylece bu kodları çalıştırdığımızda şöyle bir çıktı elde ediyoruz:
Bağlantı bilgileri kayıtlara eklendi!
Orçun Kunek
-----------
Adana
Şarkıcı
0322 123 45 67
Baraj Yolu
İsterseniz, kayit_ekle() fonksiyonundaki parametreleri kendiniz yazmak yerine kullanıcıdan almayı da tercih edebilirsiniz. Mesela şöyle bir şey yazabilirsiniz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "\nBağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
isi = raw_input("isim: ")
soy = raw_input("soyisim: ")
seh = raw_input("şehir: ")
mes = raw_input("meslek: ")
tel = raw_input("telefon: ")
adr = raw_input("adres: ")
kayit_ekle(isi, soy, seh, mes, tel, adr)
Yukarıdaki fonksiyonları kullanırken dikkat etmemiz gereken çok önemli bir nokta var. kayit_ekle() adlı fonksiyonu kullanırken argüman olarak vereceğimiz değerlerin sırası büyük önem taşıyor. Yani bu değerleri, fonksiyon tanımındaki sıraya göre yazmamız gerek. Buna göre kayit_ekle() fonksiyonunu çağırırken, ilk argümanımızın isim, ikincisinin soyisim, üçüncüsünün şehir, dördüncüsünün meslek, beşincisinin telefon, altıncısının ise adres olması gerekiyor. Aksi halde, bizim yukarıda verdiğimiz örnekte çok belli olmasa da, fonksiyondan alacağımız çıktı hiç de beklediğimiz gibi olmayabilir. Ancak takdir edersiniz ki, bu kadar fazla sayıda parametrenin sırasını akılda tutmak hiç de kolay bir iş değil. İşte bu noktada Python’daki isimli argümanlar (keyword arguments) devreye girer ve bizi büyük bir dertten kurtarır. Nasıl mı? İsterseniz yukarıda verdiğimiz örnekten yararlanalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "\nBağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
kayit_ekle(isim = "Abdurrahman",
soyisim = "Çelebi",
meslek = "Öğretmen",
tel = "0212 123 45 67",
sehir = "İstanbul",
adres = "Çeliktepe")
Gördüğünüz gibi, kayit_ekle() adlı fonksiyonumuzun argümanlarını isimleriyle birlikte çağırıyoruz. Böylece argümanları sıra gözetmeden kullanma imkânımız oluyor. Bizim örneğimizde bütün parametreler karakter dizilerinden oluştuğu için, isimli parametre kullanmanın faydası ilk bakışta pek belli olmuyor. Ama özellikle sayılar ve karakter dizilerini karışık olarak içeren fonksiyonlarda yukarıdaki yöntemin faydası daha belirgindir. Mesela şu örneğe bakalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def terfi_ettir(kisi, e_poz, y_poz, e_maas, z_orani):
print ("%s, %s pozisyonundan %s pozisyonuna "
"terfi etmiştir!" %(kisi, e_poz, y_poz))
print ("Bu kişinin %s TL olan maaşı %s TL'ye "
"yükseltilmiştir!" %(e_maas, e_maas +
(e_maas * z_orani / 100)))
terfi_ettir("Ahmet Öncel",
"İş Geliştirme Uzmanı",
"İş Geliştirme Müdürü",
3500,
25)
İşte bu örnekte, parametre/argüman sıralamasının önemi ortaya çıkar. Eğer burada mesela Ahmet Öncel argümanıyla 3500 argümanının yerini değiştirirseniz programınız hata verecektir. Çünkü bu fonksiyonda biz 3500 sayısını kullanarak aritmetik bir işlem yapıyoruz. Eğer 3500’ün olması gereken yerde bir sayı yerine karakter dizisi olursa aritmetik işlem yapılamaz... Bu arada yukarıdaki fonksiyonun sağa doğru çok fazla yayılarak çirkin bir kod görüntüsü vermemesi için satırları nasıl alta kaydırdığımıza dikkat edin.
Yukarıdaki örneği, isimli argümanları kullanarak yazarsak sıralama meselesini dert etmemize gerek kalmaz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def terfi_ettir(kisi, e_poz, y_poz, e_maas, z_orani):
print ("%s, %s pozisyonundan %s pozisyonuna "
"terfi etmiştir!" %(kisi, e_poz, y_poz))
print ("Bu kişinin %s TL olan maaşı %s TL'ye "
"yükseltilmiştir!" %(e_maas, e_maas +
(e_maas * z_orani / 100)))
terfi_ettir(e_maas = 3500,
e_poz = "İş Geliştirme Uzmanı",
kisi = "Ahmet Öncel",
y_poz = "İş Geliştirme Müdürü",
z_orani = 25)
Teknik olarak söylemek gerekirse Python fonksiyonlarında öğe sıralamasının önem taşıdığı argümanlara sıralı argüman (positional argument) adı verilir. Python fonksiyonlarında sıralı argümanlardan bolca yararlanılır. Ancak argüman sayısının çok fazla olduğu durumlarda isimli argümanları kullanmak da işinizi bir hayli kolaylaştırabilir.
Varsayılan Değerli Argümanlar¶
Önceki derslerimizden range() fonksiyonunu biliyorsunuz. Gelin isterseniz bu fonksiyona şimdi biraz daha yakından bakalım.
Hatırlarsanız range() fonksiyonunu şöyle kullanıyorduk:
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Bu kullanım bize 0’dan 10’a kadar olan sayıların listesini veriyor. Dikkat ederseniz, biz yukarıda range() fonksiyonunu tek bir argüman ile çağırdık. Ancak biz dilersek yukarıdaki fonksiyonu ikinci bir argümanla daha çağırabiliriz:
>>> range(4, 10)
[4, 5, 6, 7, 8, 9]
Bu şekilde de 4’ten 10’a kadar olan sayıların listesini elde ediyoruz. range() fonksiyonu bunların dışında üçüncü bir argüman daha alır:
>>> range(4, 10, 2)
[4, 6, 8]
Bu üçüncü argüman, range() fonksiyonunun sayıları atlayarak göstermesini sağlıyor.
Gördüğünüz gibi range() fonksiyonu şu parametrelerden oluşuyor:
range(başlangıç_değeri, bitiş_değeri, atlama_değeri)
range() fonksiyonunu kullanabilmek için bu parametreler içinde sadece “bitiş_değeri” adlı parametreye bir argüman vermemiz yeterli olacaktır:
range(10)
Öteki iki parametreyi ise boş geçebiliyoruz, çünkü o parametrelerin birer varsayılan değeri var. Bu yüzden o parametreleri belirtmesek de oluyor. O parametrelerin varsayılan değerlerinin şöyle olduğunu biliyorsunuz:
başlangıç_değeri = 0
atlama_değeri = 1
Dolayısıyla, biz range(10) yazdığımızda Python bunu range(0, 10, 1) şeklinde algılayacak ve ona göre işlem yapacaktır.
Peki varsayılan değerli argümanların bize ne gibi bir faydası var? Varsayılan değerli argümanları şuna benzetebiliriz: Diyelim ki bilgisayarınıza bir program kuruyorsunuz. Eğer bu programı ilk defa kuruyorsanız, kurulumla ilgili bütün seçeneklerin ne işe yaradığını bilmiyor olabilirsiniz. Dolayısıyla eğer program size kurulumun her aşamasında bir soru sorarsa her soruya ne cevap vereceğinizi kestiremeyebilirsiniz. O yüzden, makul bir program, kullanıcının en az seçimle programı kullanılabilir hale getirmesine müsaade etmelidir. Yani bir programın kurulumu esnasında bazı seçeneklere programı yazan kişi tarafından bazı mantıklı varsayılan değerler atanabilir. Örneğin kullanıcı programı kurarken herhangi bir kurulum dizini belirtmezse program otomatik olarak varsayılan bir dizine kurulabilir. Veya programla ilgili, kullanıcının işine yarayacak bir özellik varsayılan olarak açık gelebilir. İşte biz de yazdığımız programlarda kullanacağımız fonksiyonlara bu şekilde varsayılan değerler atarsak programımızı kullanacak kişilere kullanım kolaylığı sağlamış oluruz. Örneğin range() fonksiyonunu yazan Python geliştiricileri bu fonksiyona bazı varsayılan değerler atayarak bizim için bu fonksiyonun kullanımını kolaylaştırmışlardır. Bu sayede range() fonksiyonunu her defasında üç argüman vermek yerine tek argüman ile çalıştırabiliyoruz.
İşte biz de kendi yazdığımız fonksiyonlarda böyle varsayılan değerler belirleyebiliriz. Mesela şu örneğe bir bakalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kuvvet(sayi, kvt=2):
print sayi ** kvt
Burada, kendisine verilen bir sayının kuvvetini hesaplayan bir fonksiyon yazdık. Bu fonksiyonun varsayılan değerli bir parametresi var (kvt). Fonksiyonu şu şekilde çağırıyoruz:
kuvvet(12)
Fonksiyonu böyle çağırdığımızda otomatik olarak 12 sayısının 2. kuvveti hesaplanacaktır. Çünkü kvt parametresinin varsayılan değeri 2’dir. Ama eğer biz 12 sayısının farklı bir kuvvetini hesaplamak istersek aynı fonksiyonu şu şekilde çağırabiliriz:
kuvvet(12, 3)
Böylece 12 sayısının 3. kuvvetini hesaplamış olduk.
Gördüğünüz gibi, kuvvet() adlı fonksiyon toplam 2 parametreden oluşuyor. Bu fonksiyonu kullanabilmek için sayi parametresini mutlaka belirtmemiz gerekiyor. kvt parametresini belirtmesek de olur. Çünkü bunun varsayılan bir değeri var. Dolayısıyla biz fonksiyonu tek argümanla çağırdığımızda Python kvt parametresinin değerini 2 kabul edecektir. Eğer bizim istediğimiz şey herhangi bir sayının farklı bir kuvvetini hesaplamaksa bizim bunu açık açık belirtmemiz gerekiyor.
Gelin isterseniz bununla ilgili bir başka örnek daha verelim:
def bol(bolen, bolunen, hassas=True):
sonuc = bolen / float(bolunen)
if hassas == True:
print float(sonuc)
if hassas == False:
print int(sonuc)
Burada bol() adlı bir fonksiyon tanımladık. Bu fonksiyon toplam 3 parametre alıyor: bolen, bolunen ve hassas. Bu üç parametreden sonuncusu varsayılan bir değere sahip. Dolayısıyla bizim bu fonksiyonu en az iki argüman ile çağırmamız gerekiyor:
bol(10, 3)
Bu programı çalıştırdığımızda şu sonucu alırız:
3.33333333333
Gördüğünüz gibi, sonuç içinde ondalık kısım da görünüyor. Eğer tamsayı şeklinde bir sonuç elde etmek istersek fonksiyonumuzu şöyle çağıracağız:
bol(10, 3, False)
Bu şekilde şöyle bir sonuç alırız:
3
Dediğimiz gibi, fonksiyonumuza baktığımız zaman, bol() fonksiyonunun üç adet parametre aldığını görüyoruz. Ama sonuncu parametreye varsayılan bir değer atadığımız için, fonksiyonumuzu kullanırken sadece iki argüman vermemiz yeterli oluyor. Eğer üçüncü parametreyi belirtmezsek, bu parametrenin değeri True varsayılacaktır. Parametrenin değeri True kabul edildiği için de fonksiyonumuz hesaplamada hassas bir sonuç verir. Eğer biz bu tür bir hassasiyet istemezsek üçüncü parametre olan hassas‘ı False değeri ile çağırıyoruz.
Bu arada, yukarıdaki fonksiyonu şu şekilde tanımlayabileceğimizi de biliyoruz:
def bol(bolen, bolunen, hassas=True):
sonuc = bolen / float(bolunen)
if hassas:
print float(sonuc)
if not hassas:
print int(sonuc)
Burada if hassas: ifadesi if hassas == True: ile eşanlamlıdır. if not hassas: ise if hassas == False ile aynı anlama gelir.
Varsayılan değerli fonksiyonlar tanımlarken dikkat etmemiz gereken önemli bir kural var. Bu tür fonksiyonlarda varsayılan değerin, parametre sıralamasında en sonda gelmesi gerekiyor. Yani şöyle bir şey yazamayız:
def bol(hassas = True, bolen, bolunen):
...
Eğer varsayılan değerli argümanı en sona değil de başa veya ortaya alırsak Python bize şöyle bir hata verir:
SyntaxError: non-default argument follows default argument
Yani:
SözdizimiHatası: varsayılan değersiz argüman, varsayılan değerli argümandan sonra geliyor
Dolayısıyla kural olarak, varsayılan değere sahip argümanları parametre listesinin en sonuna yerleştirmeye özen göstermemiz gerekiyor.
İstenen Sayıda Sıralı Argüman Kullanımı¶
Fonksiyonları anlatırken şöyle bir örnek vermiştik:
def selamla(isim):
print "merhaba, benim adım %s!" %isim
Bu fonksiyon, kendisine argüman olarak verilen herhangi bir ismi, mesela Ahmet’i, merhaba, benim adım Ahmet! şeklinde ekrana döküyordu. Eğer biz hem ismin hem de soyismin ekrana dökülmesini istersek şöyle bir şey yazabiliriz:
def selamla(isim, soyisim):
print "merhaba, ben ", isim, soyisim
Bu fonksiyonu şu şekilde çağırıyoruz:
selamla("Fırat", "Özgül")
Bu kodları çalıştırdığımızda şöyle bir çıktı alırız:
merhaba, ben Fırat Özgül
Yazdığımız bu fonksiyona istediğimiz sayıda parametre ekleyebileceğimizi biliyoruz. Mesela:
def sicile_ekle(isim, soyisim, tc_kimlik,
dog_yeri, dog_tarihi, adres):
...
Bu parametreler böyle uzayıp gider... Örneğin yukarıdaki fonksiyon 6 adet parametre alıyor. Dolayısıyla biz bu fonksiyonu 6’dan az veya fazla sayıda argüman ile çağıramayız. Aksi halde Python bize hata mesajı gösterir. Peki ya biz kendimizi herhangi bir sayıyla sınırlamak istemezsek ne olacak? Yani mesela biz bir fonksiyon tanımlarken parametre sayısını önceden belirtmesek de istediğimiz kadar argümanla fonksiyonumuzu çağırabilsek olmaz mı? Örneğin şöyle bir şey yapamaz mıyız?
fonksiyon_adi(arg1, arg2, arg3, arg4, arg5, ...)
Elbette yapabiliriz. Şimdi şu kodları dikkatlice inceleyin:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def birlestir(*argumanlar):
a = ""
for i in argumanlar:
a += i + " "
print a
birlestir("Ahmet", "Öz", "Mersin",
"Mühendis", "0533 123 45 67")
Gördüğünüz gibi, bu fonksiyonun tam olarak kaç adet parametre aldığını belirtmedik. “*arg” gibi özel bir yapıdan faydalanarak bu fonksiyonun sınırsız sayıda argüman ile çağrılmasına olanak tanıdık.
Gelin isterseniz bir örnek daha yaparak durumu biraz daha netleştirelim. Hatırlarsanız yukarıda şöyle bir fonksiyon yazmıştık:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def carp(liste):
a = 1
for i in liste:
a *= i
print a
Bu fonksiyonu şu şekilde çağırıyorduk:
liste = [2, 3, 4]
carp(liste)
Böylece liste içindeki bütün sayıları birbiriyle çarpabiliyorduk. Bu fonksiyonun özelliği yalnızca tek bir parametre almasıdır. Dolayısıyla bu fonksiyonu çağırırken 1’den az veya çok sayıda argüman kullanamıyoruz. Biz bu sınırlamayı aşmak için Python’daki listelerden yararlandık. Biraz önce öğrendiğimiz “*arg” yapısını kullanarak aynı fonksiyonu şöyle de yazabiliriz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def carp(*liste):
a = 1
for i in liste:
a *= i
print a
Burada parametre sayısını kısıtlamadığımız için artık fonksiyonumuzu rahatlıkla şöyle çağırabiliriz:
carp(2, 3, 4, 5, 6, 7, 8)
Fonksiyonumuz, kendisine argüman olarak verilen bütün değerleri birbiriyle çarpacaktır...
Dilerseniz bu “*arg” yapısına biraz daha yakından bakalım. Şimdi şöyle bir şey yazdığımızı düşünün:
def fonk(*arg):
print arg
Bu fonksiyonu istediğiniz sayıda argümanla çağırabilirsiniz:
fonk("Ahmet", "Mehmet", "Veli", "Oğuz", "Ozan")
Bu fonksiyonu çalıştırdığınızda şöyle bir çıktı alırsınız:
('Ahmet', 'Mehmet', 'Veli', 'Oğuz', 'Ozan')
Gördüğünüz gibi, çıktımız bir demet. Fonksiyon çıktısını bu şekilde elde edeceğinizi bildikten sonra bu çıktıyı istediğiniz şekilde biçimlendirebilirsiniz. Mesela:
def fonk(*arg):
for sira, isim in enumerate(arg):
print "%s --> %s" %(sira, isim)
fonk("Ahmet", "Mehmet", "Veli", "Oğuz", "Ozan")
Bu fonksiyonu çalıştırdığımızda şöyle bir çıktı elde ediyoruz:
0 --> Ahmet
1 --> Mehmet
2 --> Veli
3 --> Oğuz
4 --> Ozan
Python’daki bu “*” işareti özel görevi olan bir araçtır. Bu işaret, bir dizi içindeki (bu demet olabilir, liste olabilir, vb.) bütün öğeleri tek tek fonksiyona uygular. Bu dediğimiz şeyi daha iyi anlayabilmek için şöyle bir örnek verelim:
def fonk(arg1, arg2, arg3):
print arg1, arg2, arg3
Bu basit fonksiyonu şu şekilde çağırabiliriz:
fonk("Ahmet", "Mehmet", "Ali")
Eğer istersek bu fonksiyonu, “*” işaretini de kullanarak şu şekilde de çağırabiliriz:
ls = ["Ahmet", "Mehmet", "Ali"]
fonk(*ls)
Eğer aynı fonksiyonu şu şekilde çağırırsanız hata alırsınız:
ls = ["Ahmet", "Mehmet", "Ali"]
fonk(ls)
Burada “*” işareti, listenin her bir öğesinin tek tek fonksiyona uygulanmasını sağlıyor.
Yukarıda şöyle bir örnek verdiğimizi hatırlıyorsunuz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "Bağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
kayit_ekle("Orçun", "Kunek",
"Adana", "Şarkıcı",
"0322 123 45 67", "Baraj Yolu")
Biraz önce öğrendiğimiz bilgiyi kullanarak aynı fonksiyonu şu şekilde de yazabiliriz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "Bağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
isimler = ["Orçun", "Kunek", "Adana", "Şarkıcı",
"0322 123 45 67", "Baraj Yolu"]
kayit_ekle(*isimler)
Normalde kayit_ekle() fonksiyonu 6 argüman alıyor. Biz burada bütün bu argümanları içeren bir listenin bütün öğelerini tek tek fonksiyona uyguluyoruz. Bunu yapmamızı sağlayan şey de işte biraz önce öğrendiğimiz “*” işaretidir...
Yukarıdaki örnekte, isimler listesini oluşturan öğeleri kullanıcıdan da alabileceğimizi biliyoruz. Hatta bunun için daha önce şöyle bir kod da yazmıştık:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "\nBağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
isi = raw_input("isim: ")
soy = raw_input("soyisim: ")
seh = raw_input("şehir: ")
mes = raw_input("meslek: ")
tel = raw_input("telefon: ")
adr = raw_input("adres: ")
kayit_ekle(isi, soy, seh, mes, tel, adr)
Eğer istersek, biraz önce öğrendiğimiz bilgileri kullanarak bu kodları şu şekilde de kısaltabiliriz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def kayit_ekle(isim, soyisim, sehir, meslek, tel, adres):
kayit = {}
kayit["%s %s" %(isim, soyisim)] = [sehir, meslek,
tel, adres]
print "\nBağlantı bilgileri kayıtlara eklendi!\n"
for k, v in kayit.items():
print k
print "-"*len(k)
for i in v:
print i
ls = []
sorular = ["isim: ", "soyisim: ", "şehir: ",
"meslek: ", "tel: ", "adr: "]
for i in sorular:
ls.append(raw_input(i))
kayit_ekle(*ls)
Burada önce ls adlı boş bir liste oluşturduk. Bu liste, kullanıcıdan raw_input() fonksiyonu yardımıyla alınan cevapları tutacak. Ardından da sorular adlı başka bir liste oluşturduk. Bu da kullanıcıya soracağımız soruları tutuyor. Daha sonra ise raw_input() fonksiyonunu bir for döngüsü içine sokarak, kullanıcıya sorduğumuz bütün soruların cevabını tek tek ls adlı listeye ekliyoruz. Son olarak da bu ls listesindeki bütün öğeleri tek tek kayit_ekle() adlı fonksiyona uyguluyoruz.
İstenen Sayıda İsimli Argüman Kullanımı¶
Bir önceki bölümde fonksiyonları kullanarak, istediğimiz sayıda isimsiz argümanı nasıl verebileceğimizi öğrenmiştik. Bu bölümde ise istediğimiz sayıda isimli argüman verme konusunu inceleyeceğiz.
Bildiğiniz gibi isimli argümanlar, adından da anlaşılacağı gibi, bir isimle birlikte kullanılan argümanlardır. Örneğin şu fonksiyonda isimli argümanlar kullanılmıştır:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def adres_defteri(isim, soyisim, telefon):
defter = {}
defter["isim"] = isim
defter["soyisim"] = soyisim
defter["telefon"] = telefon
for k, v in defter.items():
print("%s\t:\t%s" %(k, v))
adres_defteri(isim="Fırat",
soyisim="Özgül",
telefon="02122121212")
Burada öncelikle defter adlı bir sözlük tanımladık. Adres bilgilerini bu sözlük içine kaydeceğiz. Daha sonra bu defter adlı sözlük içinde yer alacak alanları belirliyoruz. Yazdığımız kodlara göre defter adlı sözlük içinde isim, soyisim ve telefon olmak üzere üç farklı alan bulunacak. Fonksiyon parametresi olarak belirlediğimiz isim, soyisim ve telefon öğelerine karşılık gelen değerler, defter adlı sözlükteki ilgili alanlara yerleştirilecek.
Daha sonra gelen satırda şöyle bir kod görüyoruz:
for k, v in defter.items():
print("%s\t:\t%s" %(k, v))
Burada defter sözlüğünün items() metodunu kullanarak, sözlük içindeki “anahtar” ve “değer” çiftlerini birer demet halinde alıyoruz. Eğer yukarıdaki kodu şöyle yazacak olursanız neler olup bittiği biraz daha netleşecektir:
for ogeler in defter.items():
print ogeler
('soyisim', 'Özgül')
('adres', 'İstanbul')
('telefon', '02122121212')
('eposta', 'firatozgul@frtzgl.com')
('cep', '05994443322')
('isim', 'Fırat')
Gördüğünüz gibi, yukarıdaki kod bize defter adlı sözlüğün “anahtar” ve “değer” çiflerini içeren birer demet veriyor. for k, v in defter.items() satırı ile bu demetlerdeki öğelere tek tek erişebiliyoruz. Burada “k” harfi, demetlerin ilk öğelerini, “v” harfi ise ikinci öğelerini temsil ediyor. Alt satırdaki print("%s\t:\t%s" %(k, v)) kodu yardımıyla yaptığımız şey, “k” ve “v” ile temsil edilen öğeleri biraz biçimlendirerek ekrana basmaktan ibaret... Bu satır içinde gördüğümüz “\t” harflerinin ne işe yaradığını biliyoruz. Bunlar karakter dizileri içine sekme (TAB) eklemek için kullanılan kaçış dizileridir.
Bu fonksiyona göre, “isim”, “soyisim” ve “telefon” alanlarını doldurarak fonksiyonu çalışır hale getirebiliyoruz. Şimdi yukarıdaki fonksiyona şöyle bir ekleme yapalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def adres_defteri(isim, soyisim, telefon, **arglar):
defter = {}
defter["isim"] = isim
defter["soyisim"] = soyisim
defter["telefon"] = telefon
for i in arglar.keys():
defter[i] = arglar[i]
for k, v in defter.items():
print "%s\t:\t%s" %(k, v)
adres_defteri(isim="Fırat",
soyisim="Özgül",
telefon="02122121212",
eposta="firatozgul@frtzgl.com",
adres="İstanbul",
cep="05994443322")
Burada yaptığımız eklemeler sayesinde adres_defteri() adlı fonksiyona isim, soyisim ve telefon parametrelerini yerleştirdikten sonra istediğimiz sayıda başka isimli argümanlar da belirtebiliyoruz. Burada **arglar parametresinin bir sözlük (dictionary) olduğuna özellikle dikkat edin. Bu parametre bir sözlük olduğu için, sözlüklerin bütün özelliklerine de doğal olarak sahiptir. Yukarıdaki kodları şu şekilde yazarak, arka planda neler olup bittiğini daha açık bir şekilde görebiliriz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def adres_defteri(isim, soyisim, telefon, **arglar):
print "isim:\n\t", isim
print "soyisim:\n\t", soyisim
print "telefon:\n\t", telefon
print "öteki argümanlar:\n\t", arglar
adres_defteri(isim="Fırat",
soyisim="Özgül",
telefon="02122121212",
eposta="firatozgul@frtzgl.com",
adres="İstanbul",
cep="05994443322")
Bu kodları çalıştırdığımızda şuna benzer bir çıktı alacağız:
isim:
Fırat
soyisim:
Özgül
telefon:
02122121212
öteki argümanlar:
{'adres': 'İstanbul',
'eposta': 'firatozgul@frtzgl.com',
'cep': '05994443322'}
Gördüğünüz gibi, arglar parametresi bize bir sözlük veriyor. Dolayısıyla şöyle bir kod yazmamız mümkün olabiliyor:
for i in arglar.keys():
defter[i] = arglar[i]
Bu kodlar yardımıyla arglar adlı sözlüğün öğelerini defter adlı sözlüğe ekliyoruz. Bu yapının kafanızı karıştırmasına izin vermeyin. Aslında yaptığımız şey çok basit. Sözlükler konusunu anlatırken sözlüklere nasıl öğe ekleyebileceğimizi anlattığımızı hatırlıyorsunuz:
sozluk = {}
sozluk["ayakkabı"] = 2
sozluk["elbise"] = 1
sozluk["gömlek"] = 4
Bu örnekte sozluk adlı sözlüğe ayakkabı, elbise ve gömlek adlı öğeler ekliyoruz. Bu öğelerin değerini sırasıyla 2, 1 ve 4 olarak ayarlıyoruz. Dediğim gibi, yukarıdaki örnek for i in arglar.keys()... satırıyla yaptığımız şeyden farklı değildir. Şöyle düşünün:
defter = {}
defter["adres"] = "İstanbul"
defter["eposta"] = "firatozgul@frtzgl.com"
defter["cep"] = "05994443322"
defter[i] dediğimiz şey, adres, eposta ve cep öğelerine; arglar[i] dediğimiz şey ise İstanbul, firatozgul@frtzgl.com ve 05994443322 öğelerine karşılık geliyor.
Gördüğünüz gibi, çift yıldızlı parametreler fonksiyonlara istediğimiz sayıda isimli argüman ekleme imkanı tanıyor bize... Dediğim gibi, bu parametreler bir sözlük olduğu için yukarıdaki örneği şu şekilde de yazabilirsiniz:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def adres_defteri(isim, soyisim, telefon, **arglar):
defter = {}
defter["isim"] = isim
defter["soyisim"] = soyisim
defter["telefon"] = telefon
for i in arglar.keys():
defter[i] = arglar[i]
for k, v in defter.items():
print "%s\t:\t%s" %(k, v)
sozluk = {"eposta": "firatozgul@frtzgl.com",
"adres": "İstanbul",
"cep": "05994443322"}
adres_defteri(isim="Fırat",
soyisim="Özgül",
telefon="02122121212",
**sozluk)
Burada sözlüğü önceden tanımladığımıza ve bunu fonksiyonu çağırırken doğrudan argüman olarak eklediğimize dikkat edin. Ayrıca sozluk argümanını fonksiyona yazarken yine çift yıldızlı yapıyı kullanmayı da unutmuyoruz.
Gömülü Fonksiyonlar (Built-in Functions)¶
Python’da en büyük nimetlerden biri de bu dilin yapısında bulunan gömülü fonksiyonlardır (built-in functions). Peki, bir fonksiyonun gömülü olması ne anlama gelir? “gömülü” demek, “Python’un içinde yer alan” demektir. Yani gömülü fonksiyonlar, Python programlama dilinin içinde yer alan, hazır fonksiyonlardır. Mesela daha önce öğrendiğimiz ve sık sık kullandığımız range() fonksiyonu gömülü bir fonksiyondur. Bu fonksiyon Python’un içinde, kullanılmaya hazır bir şekilde bekler. Bu fonksiyonun işlevini yerine getirebilmesi için tanımlanmasına gerek yoktur. Python geliştiricileri bu fonksiyonu tanımlamış ve dilin içine “gömmüşlerdir”. Mesela len(), enumerate() ve sum() fonksiyonları da birer gömülü fonksiyondur.
Python’daki gömülü fonksiyonların listesine http://docs.python.org/library/functions.html adresinden erişebilirsiniz. Bir program yazarken, özel bir işlevi yerine getirmeniz gerektiğinde yukarıdaki adresi mutlaka kontrol edin. Bakın bakalım sizden önce birisi tekerleği zaten icat etmiş mi? Örneğin tamsayıları (integer) ikili sayılara (binary) çevirmeniz gerekiyorsa, oturup bu işlemi yapan bir fonksiyon tanımlamaya çalışmanız boş bir çaba olur. Bunun yerine halihazırda tanımlanıp dilin içine gömülmüş olan bin() fonksiyonunu kullanabilirsiniz. Yukarıdaki adreste bunun gibi onlarca gömülü fonksiyon göreceksiniz.
Peki, gömülü fonksiyonlarla, bizim kendi yazdığımız fonksiyonlar arasında tam olarak ne fark vardır? Bir defa, gömülü fonksiyonlar oldukça hızlı ve verimlidir. Çünkü bu fonksiyonlar Python geliştiricileri tarafından özel olarak optimize edilmiştir.
İkincisi (ve belki de en önemlisi), bu fonksiyonlar her an hazır ve nazırdır. Yani bu fonksiyonları kullanabilmek için özel bir şey yapmanıza gerek yoktur. İstediğinizde veya bu fonksiyonlar lazım olduğunda doğrudan kullanabilirsiniz bu fonksiyonları. Ama bizim tanımladığımız fonksiyonlar böyle değildir. Kendi yazdığımız fonksiyonları kullanabilmek için, bu fonksiyonu içeren modülü öncelikle içe aktarmamız (import) gerekir. Şu son söylediğim şeyin kafanızı karıştırmasına izin vermeyin. Yeri ve zamanı geldiğinde “modül” ve “içe aktarmak” kavramlarından söz edeceğiz.
global Deyimi¶
Bu bölümde global adlı bir deyimden söz edeceğiz. İsterseniz global‘in ne olduğunu anlatmaya çalışmak yerine doğrudan bir örnekle işe başlayalım. Diyelim ki şöyle bir şey yazdık:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonk():
a = 5
print a
fonk()
Burada her zamanki gibi fonk() adlı bir fonksiyon tanımladık ve daha sonra bu fonksiyonu çağırdık. Sonuç olarak bu fonksiyonu çalıştırdığımızda 5 çıktısını aldık.
Gördüğünüz gibi, fonksiyon içinde a adlı bir değişkenimiz var. Şimdi şöyle bir şey yazarak bu a değişkenine ulaşmaya çalışalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonk():
a = 5
print a
fonk()
print "a'nın değeri: ", a
Bu kodları çalıştırdığımızda şöyle bir hata alırız:
Traceback (most recent call last):
File "deneme.py", line 7, in <module>
print a
NameError: name 'a' is not defined
Bu hata mesajı bize a diye bir değişken olmadığını söylüyor. Halbuki biz fonk() adlı fonksiyon içinde bu a değişkenini tanımlamıştık, değil mi? O halde neden Python a değişkenini bulamadığından yakınıyor? Hatırlarsanız bu bölümün en başında, bir fonksiyonun sınırlarının ne olduğundan söz etmiştik. Buna göre yukarıdaki fonk() adlı fonksiyon def fonk(): ifadesiyle başlıyor, print a ifadesiyle bitiyor. Bu fonksiyonun etkisi bu alanla sınırlıdır. Python’da buna isim alanı (namespace) adı verilir. Herhangi bir fonksiyon içinde tanımlanan her şey o fonksiyonun isim alanıyla sınırlıdır. Yani mesela yukarıdaki fonksiyon içinde tanımladığımız a değişkeni yalnızca bu fonksiyon sınırları dâhilinde geçerlidir. Bu alanın dışına çıkıldığında a değişkeninin herhangi bir geçerliliği yoktur. O yüzden Python yukarıdaki gibi bir kod yazdığımızda a değişkenini bulamayacaktır. İsterseniz bu durumu daha iyi anlayabilmek için yukarıdaki örneği şöyle değiştirelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonk():
a = 5
print a
fonk()
a = 10
print "a'nın değeri: ", a
Bu kodları çalıştırdığımızda ise şöyle bir çıktı alırız:
5
a'nın değeri: 10
Buradaki ilk 5 sayısı fonksiyon içindeki a‘nın değerini gösteriyor. Alt satırdaki 10 değeri ise a‘nın fonksiyon sınırları dışındaki değerini... Gördüğünüz gibi, a değişkenini fonksiyon dışında da kullanabilmek için bu değişkeni dışarıda tekrar tanımlamamız gerekiyor. Peki, biz fonksiyon içindeki a değişkenine fonksiyon dışından da erişemez miyiz? Elbette erişebiliriz. Ama bunun için global adlı bir deyimden yararlanmamız gerekir. Dilerseniz yukarıda ilk verdiğimiz örnek üzerinden giderek bu global deyimini anlamaya çalışalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonk():
a = 5
print a
fonk()
print "a'nın değeri: ", a
Kodları bu şekilde yazdığımızda Python’un bize bir hata mesajı göstereceğini biliyoruz. Şimdi bu kodlara şöyle bir ekleme yapalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonk():
global a
a = 5
print a
fonk()
print "a'nın değeri: ", a
Burada yaptığımız şey, fonksiyonu tanımladıktan sonra fonksiyon gövdesinin ilk satırına global a diye bir şey eklemekten ibaret. Bu ifade fonksiyon içindeki a adlı değişkenin “global” olduğunu, yani fonksiyonun kendi sınırları dışında da geçerli bir değer olduğunu söylüyor. Bu kodları çalıştırdığımızda şöyle bir çıktı alıyoruz:
5
a'nın değeri: 5
Gördüğünüz gibi, global deyimi bir fonksiyon içindeki değerlere fonksiyon dışından da erişmemize yardımcı oluyor...
Şimdi şöyle bir şey yazdığımızı düşünün:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
a = 10
def fonk():
a = 5
return a
print "a'nın fonksiyon içindeki değeri", fonk()
print "a'nın fonksiyon dışındaki değeri: ", a
Buradaki return deyimine takılmayın biraz sonra bunun tam olarak ne işe yaradığını göreceğiz. Biz yalnızca yukarıdaki kodların çıktısına odaklanalım.
Burada öncelikle bir a değişkeni tanımladık. Bu değişkenin değeri 10. Ardından fonk() adlı bir fonksiyon oluşturduk. Bu fonksiyon içinde değeri 5 olan bir a değişkeni daha tanımladık. Fonksiyon dışında ise, iki adet çıktı veriyoruz. Bunlardan ilki fonksiyon içindeki a değişkeninin değerini gösteriyor. İkincisi ise fonksiyon dışındaki a değişkeninin değerini... Yani bu kodları çalıştırdığımızda şöyle bir çıktı elde ediyoruz:
a'nın fonksiyon içindeki değeri 5
a'nın fonksiyon dışındaki değeri: 10
Burada fonksiyon içinde ve dışında aynı adda iki değişken tanımlamamıza rağmen, Python’daki “isim alanı” kavramı sayesinde bu iki değişkenin değeri birbirine karışmıyor. Ama bir de şu kodlara bakın:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
a = 10
def fonk():
global a
a = 5
return a
print "a'nın fonksiyon içindeki değeri", fonk()
print "a'nın fonksiyon dışındaki değeri: ", a
Burada bir önceki kodlara ilave olarak global a satırını yazdık. Bu defa çıktımız şöyle oldu:
a'nın fonksiyon içindeki değeri 5
a'nın fonksiyon dışındaki değeri: 5
Gördüğünüz gibi, global deyimi fonksiyon dışındaki a değişkenini sildi. Şimdi bu noktada kendimize şu soruyu sormamız lazım: Acaba bizim istediğimiz şey bu mu? Özellikle üzerinde birkaç farklı kişinin çalıştığı büyük projelerde böyle bir özellik ne tür sorunlara yol açabilir? Üzerinde pek çok farklı kişinin çalıştığı büyük projelerde global deyiminin büyük sıkıntılar doğurabileceği apaçık ortada. Siz programın bir yerine bir değişken tanımlamaya çalışırken, başka bir geliştirici bir fonksiyon içinde global deyimini kullanarak fonksiyon dışındaki aynı adlı değişkenlerin değerini birbirine katmış olabilir... İşte bu tür sıkıntılardan ötürü, her ne kadar faydalı bir araçmış gibi görünse de, global deyiminin sakıncaları faydalarından çoktur. O yüzden yazdığınız programlarda global deyiminden mümkün olduğunca uzak durmanızda fayda var.
return Deyimi¶
Hatırlarsanız bir önceki bölümde şöyle bir fonksiyon tanımlamıştık:
def fonk():
a = 5
return a
Dikkat ederseniz burada return diye bir şey kullandık. Bu kelime Türkçe’de “vermek, döndürmek, iade etmek” gibi anlamlara gelir. Buna göre yukarıdaki fonksiyon a değişkenini “döndürüyor”. Peki bu ne demek? Açıklayalım:
Python’da her fonksiyonun bir “dönüş değeri” vardır. Yani Python’daki bütün fonksiyonlar bir değer döndürür. Burada “döndürmek”ten kastımız bir işlemin sonucu olarak ortaya çıkan değeri vermektir. Mesela, “Bu fonksiyonun dönüş değeri bir karakter dizisidir.” veya “Bu fonksiyon bir karakter dizisi döndürür.” dediğimiz zaman kastettiğimiz şey; bu fonksiyonun işletilmesi sonucu ortaya çıkan değerin bir karakter dizisi olduğudur. Örneğin yukarıdaki fonksiyon a adlı değişkeni döndürüyor ve bu a değişkeni bir tamsayı olduğu için, fonksiyonumuzun dönüş değeri bir tamsayıdır. Peki, fonksiyonlar bir değer döndürüyor da ne oluyor? Yani bir fonksiyonun herhangi bir değer döndürmesinin kime ne faydası var? İsterseniz bunu daha iyi anlayabilmek için yukarıdaki örneği bir de şöyle yazalım:
def fonk():
a = 5
print a
Burada herhangi bir değer döndürmüyoruz. Yaptığımız şey bir a değişkeni belirleyip, print deyimini kullanarak bunu ekrana bastırmaktan ibaret. Bu arada şunu da belirtelim: Her ne kadar biz bir fonksiyonda açık açık bir değer döndürmesek de o fonksiyon otomatik olarak bir değer döndürecektir. Herhangi bir değer döndürmediğimiz fonksiyonlar otomatik olarak None diye bir değer döndürür. Bunu şu şekilde test edebiliriz:
print fonk()
Fonksiyonu bu şekilde çağırdığımızda şöyle bir çıktı aldığımızı göreceksiniz:
5
None
İşte burada gördüğümüz None değeri, fonk() adlı fonksiyonumuzun otomatik olarak döndürdüğü değerdir. Yukarıdaki fonksiyonu print olmadan da çağırabileceğimizi biliyorsunuz:
fonk()
Bu defa a değişkeninin değeri ekrana dökülecek, ancak None değerini göremeyeceğiz. Şimdi şu fonksiyona bakalım:
def fonk():
a = 5
return a
fonk()
Burada ise ekranda herhangi bir çıktı göremeyiz. Bunun nedeni, bu fonksiyonda herhangi bir “print” işlemi yapmıyor olmamızdır. Biz burada sadece a değişkenini döndürmekle yetiniyoruz. Yani ekrana herhangi bir çıktı vermiyoruz. Bu fonksiyondan çıktı alabilmek için fonksiyonu şöyle çağırmamız gerekir:
print fonk()
“Peki, bütün bu anlattıkların ne işe yarar?” diye sorduğunuzu duyar gibiyim...
Bir defa şunu anlamamız lazım: print ve return aynı şeyler değildir. print deyimi bir mesajın ekrana basılmasını sağlar. return deyimi ise herhangi bir değerin döndürülmesinden sorumludur. Siz bir fonksiyondan bir değer döndürdükten sonra o değerle ne yapacağınız tamamen size kalmış. Eğer tanımladığınız bir fonksiyonda bir değer döndürmek yerine o değeri ekrana basarsanız (yani print deyimini kullanırsanız) fonksiyonun işlevini bir bakıma kısıtlamış olursunuz. Çünkü tanımladığınız bu fonksiyonun tek görevi bir değeri ekrana basmak olacaktır. Ama eğer o değeri ekrana basmak yerine döndürmeyi tercih ederseniz, fonksiyonu hem ekranda bir mesaj göstermek için hem de başka işler için kullanabilirsiniz. Bunu anlayabilmek için şöyle bir örnek verelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def ekrana_bas():
a = 5
print a
print "a değişkeninin değeri: %s" %ekrana_bas()
Bu kodları çalıştırdığımızda şöyle bir çıktı alırız:
5
a değişkeninin değeri: None
Görüyorsunuz, işler hiç de istediğimiz gibi gitmedi. Halbuki biz a değişkeninin değeri: 5 gibi bir çıktı alacağımızı zannediyorduk.
Daha önce de dediğimiz gibi, bir fonksiyondan herhangi bir değer döndürmediğimizde otomatik olarak None değeri döndürüldüğü için çıktıda bu değeri görüyoruz. Ama eğer yukarıdaki fonksiyonu şu şekilde tanımlasaydık işimiz daha kolay olurdu:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def ekrana_bas():
a = 5
return a
print "a değişkeninin değeri: %s" %ekrana_bas()
Gördüğünüz gibi, bu defa istediğimiz çıktıyı aldık. Bir de şu örneğe bakın:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def sayi_isle():
sor = input("bir sayı girin: ")
return sor
sayi = sayi_isle()
print "girdiğiniz sayı: %s" %sayi
if sayi % 2 == 0:
print "girdiğiniz sayı çifttir"
else:
print "girdiğiniz sayı tektir"
print "girdiğiniz sayının karesi: %s" %sayi ** 2
print "girdiğiniz sayının küpü: %s" %sayi ** 3
Burada sayi_isle() adlı fonksiyonda kullanıcıya bir sayı sorup bu sayıyı döndürüyoruz. Daha sonra fonksiyonu çağırırken, bu döndürdümüz değerle istediğimiz işlemi yapabiliyoruz. İsterseniz bu fonksiyonu bir de return yerine print ile tanımlamayı deneyin. O zaman ne demek istediğimi gayet net bir biçimde anlayacaksınız.
Fonksiyonlarda pass Deyimi¶
Hatırlarsanız hata yakalama konusunu işlerken pass adlı bir deyimden söz etmiştik. İsterseniz o deyimi tekrar hatırlayalım.
“Pass” kelimesi Türkçe’de “geçmek, aşmak” gibi anlamlara gelir. Python’da ise bu deyim herhangi bir işlem yapmadan geçeceğimiz durumlarda kullanılır. Peki, bu ne demek?
Şu örneğe bir bakalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def deneme():
liste = []
while True:
a = raw_input("Giriniz: ")
if a == "0":
pass
else:
liste.append(a)
print liste
deneme()
Burada gördüğümüz gibi, eğer kullanıcı 0 değerini girerse, bu değer listeye eklenmeyecek, Python hiçbir şey yapmadan bu satırı atlayacaktır. İşte pass buna benzer durumlarda, “hiçbir şey yapmadan yola devam et!” anlamı katar kodlarımıza.
Dediğimiz gibi, pass deyiminin bu görevlerini daha önce öğrenmiştik. pass deyimini yukarıdaki durumlar dışında bir de şöyle bir durumda kullanabilirsiniz: Diyelim ki bir program yazıyorsunuz. Bu programda bir fonksiyon tanımlayacaksınız. Fonksiyonun isminin ne olacağına karar verdiniz, ama fonksiyon içeriğini nasıl yazacağınızı düşünmediniz. Eğer program içinde sadece fonksiyonun ismini yazıp bırakırsanız programınız çalışma sırasında hata verecektir. İşte böyle bir durumda pass deyimi imdadınıza yetişir. Bu deyimi kullanarak şöyle bir şey yazabilirsiniz:
def bir_fonksiyon():
pass
Fonksiyon tanımlarken fonksiyon gövdesini boş bırakamazsınız. Çünkü dediğimiz gibi, eğer gövdeyi boş bırakırsanız programınız çalışmaz. Böyle bir durumda, yukarıda gösterdiğimiz gibi fonksiyonu tanımlayıp gövde kısmına da bir pass deyimi yerleştirebilirsiniz. Daha sonra gövde kısmına ne yazacağınıza karar verdiğinizde bu pass deyimini silebilirsiniz.
Fonksiyonların Belgelendirilmesi¶
Her zaman söylediğimiz gibi, kod bir kez yazılır, bin kez okunur. Bu yüzden yazdığınız kodların anlaşılır olması her şeyden önemlidir. Program yazarken, yazdığınız kodların işlevinin yanısıra anlaşılır olmasına da dikkat etmeniz gerekir. Program yazarları, yazdıkları kodların daha kolay anlaşılmasını sağlamak için bazı yardımcı araçlardan da faydalanır. Mesela önceki derslerimizde gördüğümüz yorum (comment) kavramı bu yardımcı araçlardan biridir.
Python programcılarının, okunaklılığı artırmak için kullanabileceği bir başka yardımcı araç da belgelendirme dizileridir (docstring). Dilerseniz hemen bununla ilgili küçük bir örnek verelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def fonk():
"""boş bir fonksiyondur. Hiçbir
işe yaramaz..."""
pass
Gördüğünüz gibi, belgelendirme dizisini fonksiyon tanımının hemen ardından getiriyoruz. Belgelendirme dizilerinde üç tırnak kullanmak adettendir.
Bir fonksiyona ait belgelendirme dizisine erişmek için şu yöntemi kullanıyoruz:
Mesela sum() fonksiyonunun belgelendirme dizisine ulaşalım:
>>> print sum.__doc__
sum(sequence[, start]) -> value
Returns the sum of a sequence of numbers (NOT strings) plus the value
of parameter 'start' (which defaults to 0). When the sequence is
empty, returns start.
Kendi yazdığımız fonksiyonların belgelendirme dizilerine de aynı şekilde ulaşabiliriz. Önce fonksiyonumuzu tanımlayalım:
>>> def fonk():
... """boş bir fonksiyondur. Hiçbir
... işe yaramaz..."""
... pass
Şimdi de fonksiyonumuzun belgelendirme dizisine ulaşalım:
>>> print fonk.__doc__
boş bir fonksiyondur. Hiçbir
işe yaramaz...
Gelin isterseniz biraz daha anlamlı bir örnek verelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def not_ortalamasi_hesapla(ogrenci_sayisi=5):
"""Not ortalaması hesaplayan bir fonksiyon.
Bu fonksiyonun aldığı tek argüman
kullanıcıya kaç kez not bilgisi sorulacağını
gösterir."""
deneme = 0
toplam = []
while deneme < ogrenci_sayisi:
deneme += 1
toplam.append(int(raw_input("%s. öğrencinin notu: "
% deneme)))
print "Toplam %s öğrenci var." % deneme
print ("Bu öğrencilerin not ortalaması: %s"
%(sum(toplam)/deneme))
not_ortalamasi_hesapla()
Gördüğünüz gibi, belgelendirme dizileri bize yazdığımız bir fonksiyonun ne işe yaradığını anlatma imkanı sağlıyor. Belgelendirme dizileri özellikle yazdığımız kodları okuyan başkaları için kıymetlidir. Belgelendirme dizileri sayesinde, yazdığımız kodları okuyanlar, yazdığımız şeyin ne işe yaradığı hakkında fikir sahibi olacaktır.
Yukarıdaki kodlarda yer alan belgelendirme dizisini ekrana basmak için kodlarınıza şöyle bir satır eklemelisiniz:
print not_ortalamasi_hesapla.__doc__
Bu arada, yazdığınız belgelendirme dizilerinin de Python’un girintileme kurallarına uygun olması gerektiğine dikkat edin.
Böylece fonksiyonlar konusunu tamamlamış olduk. Artık yeni ve çok önemli bir konu olan “Modüllere” başlayabiliriz. Ama tabii ki önce bölüm sorularımız...
Bölüm Soruları¶
1. Esasında siz, bu bölümde incelediğimiz fonksiyon konusuna hiç de yabancı sayılmazsınız. Bu bölüme gelinceye kadar pek çok fonksiyon öğrenmiştik. Mesela daha önceki derslerimizden hangi fonksiyonları hatırlıyorsunuz?
2. Python’daki sum() fonksiyonunun yaptığı işi yapan bir fonksiyon yazın. Yazdığınız fonksiyon bir liste içindeki sayıların toplamını verebilmeli.
3. Kullanıcıya isim soran bir program yazın. Bu program kullanıcının ismini ekrana dökebilmeli. Ancak eğer kullanıcının girdiği isim 5 karakterden uzunsa, 5 karakterden uzun olan kısım ekrana basılmamalı, onun yerine ”...” işareti gösterilmelidir. Örneğin kullanıcıdan alınan isim Abdullah ise programınız “Abdul...” çıktısını vermeli.
4. Bir önceki soruda yazdığınız programda kullanıcı, içinde Türkçe karakterler bulunan bir isim girdiğinde programınızda nasıl bir durum ortaya çıkıyor? Örneğin programınız “Işıl” ismine nasıl bir tepki veriyor? Sizce bunun sebebi nedir?
5. Yukarıdaki fonksiyonlarla ilgili şöyle bir örnek vermiştik:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def tek():
print "Girdiğiniz sayı bir tek sayıdır!"
def cift():
print "Girdiğiniz sayı bir çift sayıdır!"
sayi = raw_input("Lütfen bir sayı giriniz: ")
if int(sayi) % 2 == 0:
cift()
else:
tek()
Bu kodlara şöyle bir baktığınızda, aslında bu kodları şu şekilde de yazabileceğimizi farketmişsinizdir:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
sayi = raw_input("Lütfen bir sayı giriniz: ")
if int(sayi) % 2 == 0:
print "Girdiğiniz sayı bir çift sayıdır!"
else:
print "Girdiğiniz sayı bir tek sayıdır!"
Bu kodları böyle değil de fonksiyon içinde yazmamızın sizce ne gibi avantajları vardır?
6. Argüman ile parametre arasındaki farkı açıklayın.
7. Standart bir kurulum betiğini taklit eden bir program yazın. Örneğin programınız şu aşamaları gerçekleştirebilmeli:
- Kullanıcıya, “Kuruluma hoşgeldiniz!” mesajı göstermeli,
- Kullanıcıya bir lisans anlaşması sunmalı ve bu anlaşmanın şartlarını kabul edip etmediğini sormalı,
- Eğer kullanıcı lisans anlaşmasının şartlarını kabul ederse kuruluma devam etmeli, aksi halde kurulumdan çıkmalı,
- Kullanıcıya, “standart paket”, “minimum kurulum” ve “özel kurulum” olmak üzere üç farklı kurulum seçeneği sunmalı,
- Kullanıcının seçimine göre, programda kurulu gelecek özelliklerin bazılarını etkinleştirmeli veya devre dışı bırakmalı,
- Programın sistem üzerinde hangi dizine kurulacağını kullanıcıya sorabilmeli,
- Kurulumdan hemen önce, programın hangi özelliklerle kurulmak üzere olduğunu kullanıcıya son kez bildirmeli ve bu aşamada kullanıcıya kurulumdan vazgeçme veya kurulum özelliklerini değiştirme imkanı vermeli,
- Eğer kullanıcı kurulum özelliklerini değiştirmek isterse önceki aşamaya geri dönebilmeli,
- Eğer kullanıcı, seçtiği özelliklerle kurulumu gerçekleştirmek isterse program kullanıcının belirlediği şekilde sisteme kurulabilmeli,
- Son olarak kullanıcıya kurulumun başarıyla gerçekleştirildiğini bildiren bir mesaj göstermeli.
Not: Bu adımları kendi hayal gücünüze göre değiştirebilir, bunlara yeni basamaklar ekleyebilirsiniz.
8. Fonksiyonlar konusunu anlatırken şöyle bir örnek vermiştik:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def tek():
print "Girdiğiniz sayı bir tek sayıdır!"
def cift():
print "Girdiğiniz sayı bir çift sayıdır!"
sayi = raw_input("Lütfen bir sayı giriniz: ")
if int(sayi) % 2 == 0:
cift()
else:
tek()
Bu programın zayıf yönlerini bulmaya çalışın. Sizce bu program hangi durumlarda çöker? Bu programın çökmesini engellemek için ne yapmak gerekir?