Python (6. Bölüm)

Wiki.Pardus-Linux.Org sitesinden

Git ve: kullan, ara

Forum'da bu konunun tartışma adresi: http://forum.pardus-linux.org/viewtopic.php?t=10478&highlight=


Konu başlıkları

Python'da Fonksiyonlar

Giriş

Bazen kodları her defasında tekrar tekrar yazmak yerine, bir kez yazıp tekrar tekrar kullanabilmek isteriz. Eğer böyle bir şey istiyorsak Python'da fonksiyonları kullanmamız gerekiyor. Python'un içinde gömülü vaziyette duran onlarca fonksiyon bulunur. Mesela len() ve range() birer fonksiyondur.

Fonksiyon Tanımlama

Python, kendisinde var olan fonksiyonların yanısıra bizim de yeni fonksiyon tanımlamamıza olanak tanır. Fonksiyonları tanımlarken "def" adlı bir parçacıktan yararlanacağız. Bu "def" parçacığının hemen ardından ise fonksiyonumuzun adını belirlememiz gerekiyor... Bu adı belirlerken Türkçe karakter kullanmamamız gerektiğini hatırlatmaya gerek yok herhalde.

Hemen bir örnek verelim:

def ilk_fonksiyonumuz():

Gördüğünüz gibi önce "def" parçacığı yardımıyla Python'a bir fonksiyon tanımlayacağımızı bildirdik. Daha sonra bu fonksiyona "ilk_fonksiyonumuz" adını verdik. Tabii siz isterseniz fonksiyonunuza başka adlar da verebilirsiniz. Bu arada ifadenin en sonuna iki nokta üst üsteyi eklemeyi de unutmuyoruz.

Şu anda fonksiyonumuzun fonksiyon olduğu ve adının ne olduğu belli. Ama ne yaptığı, ne işe yaradığı belli değil... O halde devam edelim:

def ilk_fonksiyonumuz():
     	 print "Ben Python! Monty Python!"

Aslında şu an itibariyle ilk fonksiyonumuzu tanımlamış bulunuyoruz. İsterseniz bu kodu Python komut satırında yazabiliriz. Peki nasıl?

Komut Satırında Fonksiyon Tanımlama

Her zamanki gibi ALT+F2 tuşlarına basıp, çıkan ekrana "konsole" yazıyoruz ve siyah ekranda "python" yazarak Python komut satırını başlatıyoruz.

Komut satırında:

def ilk_fonksiyonumuz():

yazıp enter'e bastığımızda "..." işaretini görürüz. Bu, Python'un bizden yeni bir satır yazmamızı beklediği anlamına geliyor. Şimdi de

print "Ben Python! Monty Python!"

satırını yazacağız. Ama bu satırı girintili yazmamız gerekiyor. "Space" tuşuna dört kez basarak girintileme işlemini yapıyoruz. Şimdi;

print "Ben Python! Monty Python!"

satırını yazabiliriz.

Bu satırı da yazdıktan sonra iki kez enter tuşuna basarak ">>>" işaretinin belirmesini bekliyoruz. Bu işareti gördükten sonra:

ilk_fonksiyonumuz()

yazıp enter'e bastığımızda fonksiyonumuzun içeriği ekrana yazılacaktır...

Metin Düzenleyicide Fonksiyon Tanımlama

Peki ya bu fonksiyonu bir metin dosyasına kaydetmek istersek ne yapacağız? (ki doğrusu da budur aslında)

Hemen boş bir kwrite dosyası açıp içine şunları yazıyoruz:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def ilk_fonksiyonumuz():
	print "Ben Python! Monty Python!"

Şimdi son bir satır daha eklememiz gerekiyor. Komut satırında yazarken kodumuz bu satır olmadan da çalışıyordu, ama metin dosyasına şöyle bir satır eklememiz gerekiyor:

ilk_fonksiyonumuz()

Metnimiz en son şöyle görünecek:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def ilk_fonksiyonumuz():
	print "Ben Python! Monty Python!"
ilk_fonksiyonumuz()

Bu son satır, yazdığımız fonksiyonu çağırmamızı sağlıyor. Bu metin dosyasını ilk_fonksiyon.py adıyla bilgisayarımıza kaydediyoruz. Artık konsol'da

python ilk_fonksiyonumuz.py

komutuyla fonksiyonumuzu çalıştırabiliriz.

Fonksiyonlarda Parametreler

Gördüğünüz gibi tanımladığımız fonksiyonda içi boş parantezler kullandık: "def ilk_fonksiyonumuz()"

Bu parantezlerin içine, yerine göre bazı ifadeler, yani parametreler ekleme şansımız da var... Ancak bu parantezlerin içi boş da olsa, dolu da olsa fonksiyon tanımlarken bu parantezleri koymayı unutmamamız gerekiyor. Peki bu parantezlerin içine neler yazabiliriz? Mesela çarpma yapan bir fonksiyon tanımlayacaksak eğer, birbirleriyle çarpılacak değerleri yazabiliriz. Tabii bu değerler mutlaka sayı cinsinden olacak diye bir kaide yok... Biz değerlerimizi "değişken" olarak da tanımlayabiliriz :

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def carpma(a, b):
	print a * b
carpma(124, 345)

Dikkat ederseniz, son satırda, "124" ve "345" sayılarını kullanarak sırasıyla "a" ve "b" değişkenlerini tanımlamış olduk. Bu fonksiyon çalıştırıldığında ekrana 124 x 345 işleminin sonucu yazdırılacaktır.

Yukarıdaki örnekte değişkenlerin değerini (124 ve 345) son satırda parantez içine yazarak bunları doğrudan tanımlamış olduk. Ama biz istersek bu değişkenleri ayrı olarak da tanımlayabiliriz:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def carpma(a, b):
	print a * b
a = 124
b = 345
carpma(a, b)

Burada a ve b değişkenlerini print ifadesinin alt hizasına yazmadığımıza dikkat edin.. Eğer bu değerleri print ifadesinin alt hizasına yazarsak Python bize pislik yapacak, değişkenleri tanımlamadığımızı iddia edecektir...

Ama istersek yukarıdaki kodu şu şekilde de yazabiliriz:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def carpma(a, b):
	a = 124
	b = 345
	print a * b
carpma(a, b)

Gördüğünüz gibi, a ve b değişkenlerini fonksiyonu tanımladıktan hemen sonra belirlersek print ifadesinin üst hizasına yazabiliyoruz.. Tabii şimdi bunları satırın en başına alırsanız Python bu defa da size başka bir bahaneyle pislik yapacak, "Abi bizim buralarda iki nokta üst üste koyup enter'e bastıktan sonraki ifade girintili yazılır.. Şimdi eski köye yeni adet getirme," diye bir hata mesajı verecektir.

Şimdi başka bir örnek daha görelim:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def liste_kontrol(liste):
	if liste == []:
		print "listeniz şu anda boş"
	else:
		print "listenizde şu anda", liste, "adlı öğeler görünüyor"		
liste = ["ahmet", "mehmet"]
liste_kontrol(liste)

Bu örnekte de liste öğelerini ayrı olarak tanımladık. Tabii biraz önceki örnekte olduğu gibi istersek bu öğeleri fonksiyonun içine de yedirebiliriz:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def liste_kontrol(liste):
	if liste == []:
		print "listeniz şu anda boş"
	else:
		print "listenizde şu anda", liste, "adlı öğeler görünüyor"
liste_kontrol(liste = ["ahmet", "mehmet"])

Daha önce anlattığımız gibi, bu fonksiyonları metin düzenleyici yerine doğrudan Python komut satırına da yazabiliriz. Eğer bu kodları komut satırına yazarsak, mesela yukarıdaki çarpma fonksiyonunu çağırırken çarpılacak değerleri isteğimize göre değiştirebiliriz. Hemen deneyelim:

Python komut satırını açıp ">>>" işaretinden hemen sonra;

def carpma(a, b):

yazıp enter'e basıyoruz. Şimdi dört kez "space" tuşuna basarak girinti veriyoruz. Girintiyi verdikten sonra şu kodu yazıyoruz:

print a * b

Hemen ardından iki kez enter tuşuna basarak ">>>" işaretinin tekrar belirmesini sağlıyoruz. Şimdi de mesela şu komutu yazarak az evvel tanımladığımız fonksiyonumuzu çalıştırıyoruz:

carpma(45, 56)

Yukarıdaki komutta 45 ile 56 sayısını çarpmış olduk. İsterseniz parantez içindeki bu değerleri, yani parametreleri, istediğimiz gibi değiştirebiliriz. Mesela şöyle yapabiliriz:

carpma(555, 444)

Şimdi şöyle bir şey deneyelim. Önce boş bir kwrite belgesi açalım ve içine şunları yazalım:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def carpma(a, b):
	print a * b

Gördüğünüz gibi bu kod yukarıda yazdığımız kodla aynı... Tek fark en sonda "carpma(124, 345) gibi bir ifade kullanmadık. Bu dosyayı "fonk.py" adıyla kaydedelim.

Şimdi de başka bir boş kwrite belgesi açıp içine şunları yazalım:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
from fonk import carpma
carpma(34,45)

Bu dosyayı da istediğimiz bir adla kaydedebiliriz. Mesela "deneme.py" diyelim...

Şimdi bu "deneme.py" adlı dosyayı çalıştırdığımız zaman 34 ve 45 sayılarının birbirleriyle çarpıldığını görürüz... Halbuki deneme dosyası içinde herhangi bir çarpma işlemi tanımlamadık... Durum böyle olduğu halde çarpma yapabilmemizin nedeni daha önce tanımladığımız "fonk" isimli fonksiyonu "deneme" isimli belgemize "davet etmiş" veya "yüklemiş" olmamız... Ya da İngilazca olarak ifade edersek, "import etmiş" olmamız... Hatırlarsanız o "fonk" isimli fonksiyon içinde zaten bir çarpma işlemi tanımlamıştık... Dolayısıyla "deneme" isimli belgede tekrar çarpma işlemi tanımlamamıza gerek kalmadı... Peki bu "davet etme" işini nasıl yaptık?

Dikkat ederseniz, "deneme.py" isimli dosyamızın üçüncü satırı şöyle:

from fonk import çarpma

Bu Python'ca ifadenin Türkçesi şu: "fonk isimli modülden çarpma isimli fonksiyonu yükle (veya davet et veya import et)"

Bizim konumuz "Python'da Fonksiyonlar" idi... Peki şimdi bu "modül" lafı da nereden çıktı... Bu durumu şöyle açıklayabiliriz:

Bu bölümün en başında, "def" parçacığını kullanarak Python'da fonksiyon tanımlamayı öğrenmiştik. Aynı belge içinde bu "def" parçacığını kullanarak pek çok fonksiyon tanımlayabiliriz. İşte bu bir veya birden fazla fonksiyon hep birlikte "modül" denen şeyi oluşturuyor... Yani aslında "modül", fonksiyonlardan oluşmuş bir bütünün adı... Python'da modül kavramını bir sonraki bölümde daha ayrıntılı bir şekilde inceleyeceğiz... Bizim örneğimizde "def" parçacığıyla tanımlanmış "carpma" isimli blok bir fonksiyon; dosyamızın adı olan "fonk" ise bir modül olmuş oluyor...

Bu arada dikkat edin, yukarıdaki modülü ilk yüklediğimizde, çalışma klasörümüzde .pyc uzantılı bir dosya daha oluştu. Python bu dosyayı oluşturarak modülün bir dahaki sefere daha hızlı yüklenmesini sağlıyor...

Şimdi konumuza dönelim... Ne demiştik:

"fonk isimli modülden çarpma isimli fonksiyonu yükle (veya davet et veya import et)"

Yani Python'ca söylemek gerekirse:

from fonk import carpma

Bu sayede fonk isimli modülün içinde yer alan çarpma isimli fonksiyonu belgemizin içine davet ettik... Bu "çarpma" isimli fonksiyon da çarpma işlemi yaptığı için, girdiğimiz "34" ve "45" sayılarını birbiriyle çarptı...

Hatırlarsanız çok önceden yazdığımız bir hesap makinesi programında, bölme işlemlerini hatasız yapabilmek için

from __future__ import division

satırını eklemiştik... İşte şimdi yaptığımız şey de buna çok benziyor... İsterseniz /usr/lib/python2.4/ klasörünün içine bakın. Orada "__future__.py" adlı bir dosya göreceksiniz. Bu dosyayı açtığınızda onun içinde de "division" adlı bir satır olduğunu görürsünüz... İşte bu "from __future__ import division" komutuyla "__future__" dosyası içindeki "division" satırını kendi belgemizin içine davet etmiş oluyoruz... Dediğimiz gibi, bu konuyu bir sonraki bölümde daha ayrıntılı bir şekilde inceleyeceğiz.

Yukarıdaki fonksiyonu şu şekilde de çalıştırabiliriz:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
import fonk
fonk.carpma(34,45)

Gördüğünüz gibi, "fonk" adlı modülün içinden belirli bir fonksiyonu programımıza davet etmek yerine, "fonk" adlı modülün kendisini de davet edebiliyoruz. Bu şekilde "fonk" modülü içinde ne kadar fonksiyon varsa programımıza davet edilecektir. Ancak dikkat ederseniz, bu şekilde fonksiyonumuzu parçacık olarak kullanıyoruz. Yani "fonk.carpma()" şeklinde... Tıpkı bir önceki bölümün konusu olan "Listeler, Demetler ve Sözlükler"de gördüğümüz gibi... Hatırlarsanız orada da bazı parçacıklar kullanarak işimizi görüyorduk...

Fonksiyon İçindeki Değişkenlerin Okunma Sırası

Şimdi şu örneği ele alalım:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def merhaba(arkadas):
	print "Merhaba", arkadas
arkadas = "Kezban"
merhaba(arkadas)

Her şey normal... Çıktımız:

Merhaba Kezban

olacaktır.

Yukarıdaki örneğe ufak bir ekleme yapalım:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def merhaba(arkadas):
	print "Merhaba", arkadas
arkadas = "Kezban"
arkadas = "Mücella"
merhaba(arkadas)

Sizce Python burada kimi arkadaştan sayacak? Kezban'ı mı yoksa Mücella'yı mı?

Cevap: Mücella!

Peki bunun nedeni nedir?

Cevap: Python fonksiyonlarda değişkenleri okumaya sondan başlar... Yukarıdaki örnekte arkadas = "Mücella" ifadesinin altına arkadas = "Ahmet" ifadesini eklerseniz, Python bu kez "Ahmet"i dikkate alacaktır... Çünkü bu kez en sonda "Ahmet" değeri olmuş olacak...

Şimdi şu örneğe bakın:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def merhaba(arkadas):
	print "Merhaba", arkadas
	arkadas = "Kezban"
	print "Artık benim yeni arkadaşım", arkadas
arkadas = "Mücella"
merhaba(arkadas)

Bu örnekte aynı adla iki farklı değişken tanımladık. Burada Python'un değişkenleri okurken nasıl bir sıra takip ettiğine dikkat edin...

Ayrıca gördüğünüz gibi,

arkadas = "Kezban"

satırını,

arkadas = "Mücella"

satırından farklı olarak print ifadesinin tam altına denk getirdik. Çünkü kodumuz henüz bitmedi. Daha başka satırlar da eklemeyi düşünüyoruz kodumuza. Bu değişkeni satırın en başına alırsak Python beyin üstü betona çakılacaktır. Çünkü bu değişkeni satır başına alırsak, Python bizim artık son kodu yazdığımızı, bu kodun hemen ardından "merhaba(arkadas)" satırını ekleyip fonksiyonu çağırmak suretiyle mevcut fonksiyon bloğunu sona erdireceğimizi zanneder... Halbuki bizim yazacak birkaç satırımız daha var... İsterseniz bu ifadeyi satır başına alarak Python'un bize ne tür küfürler edeceğini görebilirsiniz...

Tabii ki biz bu iki değişkene farklı adlar vererek çok daha kolay biçimde işimizi halledebiliriz:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def merhaba(arkadas, ark):
	print "Merhaba", ark
	print "Artık benim yeni arkadaşım", arkadas
arkadas = "Kezban"
ark = "Mücella"
merhaba(arkadas, ark)

"global" ifadesi

Şimdi kendimize şöyle bir soru soralım:

Acaba fonksiyon bloğu içinde tanımladığımız bir değişken, mevcut fonksiyon haricinde de aynı adla kullanılabilir mi? Yani diyelim ki bir fonksiyon oluşturduk ve bu fonksiyon içinde bir x değişkeni tanımladık. Daha sonra başka bir fonksiyon daha oluşturduk ve bir önceki fonksiyonda tanımladığımız x değişkenini bu yeni fonksiyon içinde de kullanmak istiyoruz. Amacımız mesela şöyle bir şey yapmak:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def matematik_toplama():
	soru = input("Lütfen bir sayı girin: ")
	soru2 = input("Lütfen başka bir sayı daha girin: ")
	print "Bu iki sayı toplanırsa şu çıkar:"
	print soru + soru2
matematik_toplama()
 
def matematik_carpma():
	print "bu iki sayı çarpılırsa şu çıkar:"
	print soru * soru2
matematik_carpma()

Bu kodları bu şekilde çalıştırırsak Python bize bir hata mesajı gösterecektir. Çünkü bir fonksiyon içinde tanımlanan değişkenler sadece o fonksiyonun sınırları içinde geçerlidir. Yani bir fonksiyon içinde tanımlanan bir değişken başka bir fonksiyon içinde kullanılamaz. Eğer biz bir fonksiyon içinde tanımladığımız bir değişkeni o fonksiyon dışında da kullanmak istiyorsak şöyle bir satır eklemeliyiz:

global [değişken_adı]

Bunu yukarıdaki kodlara uygularsak şöyle olmalı:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def matematik_toplama():
	global soru, soru2
	soru = input("Lütfen bir sayı girin: ")
	soru2 = input("Lütfen başka bir sayı daha girin: ")
	print "Bu iki sayı toplanırsa şu çıkar:"
	print soru + soru2
matematik_toplama()
 
def matematik_carpma():
	print "bu iki sayı çarpılırsa şu çıkar:"
	print soru * soru2
matematik_carpma()

Gördüğünüz gibi, "global" ifadesi, değişkenin değerinin bir nevi "evrensel" olmasını sağlıyor...

Bir örnek daha verelim:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def deneme(arkadas):
	print "Merhaba", arkadas
	arkadas = "Kezban"
	print "Benim yeni arkadaşım artık", arkadas
arkadas = "Mücella"
deneme(arkadas)	
print "evet, onun arkadaşı artık", arkadas

Bu kodu bu haliyle çalıştırırsak çıktımız şöyle olacaktır:

Merhaba Mücella
Benim yeni arkadaşım artık Kezban
evet, onun arkadaşı artık Mücella

Son satırdaki mantık hatasını görüyorsunuz. Olması gereken "Mücella" değil, "Kezban"...

Bu durumu düzeltmek için global ifadesini kullanacağız:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def deneme():
	global arkadas
	print "Merhaba", arkadas
	arkadas = "Kezban"
	print "Benim yeni arkadaşım artık", arkadas
arkadas = "Mücella"
deneme()	
print "evet, onun arkadaşı artık", arkadas

Dikkat ederseniz, global ifadesini kullanabilmek için fonksiyon tanımlarındaki parantez içi parametreleri kaldırdık. Aksi halde Python bize bir hata mesajı gösterecektir.

"return" ifadesi

Bu ifadenin ne işe yaradığını anlamak için şu örneklere bakalım:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def return_deneme(a,b):
	if a < b:
		return a
	else:
		return b
print return_deneme(34, 45)

Gördüğünüz gibi burada "return" ifadesi yarattığımız koşulun sonucuna göre ya a değişkenini ya da b değişkenini "döndürüyor"; yani bize çıktı olarak veriyor...

Bir de şu örneğe bakalım:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def deneme():
	liste = ["Ayva", "Çiçek", "Açmış", "Yaz mı", "Gelecek"]
	return liste
print deneme()

Bu örnekte de "return" ifadesi listenin öğelerini ekrana döküyor.. Bu arada fonksiyonun sonuna bir "print" ifadesi eklediğimize dikkat edin.

Eğer fonksiyonumuzu aşağıdaki şekilde yazarsak, Python bize "none" diye bir çıktı verecektir:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def deneme():
	return 
print deneme()

Bu "none" değeri, fonksiyonun geçerli ve doğru olduğunu, ama hiçbir şey içermediğini anlatır...

"Return" ifadesinin ikinci bir işlevi ise bir fonksiyonun işletilmesine engel olmaktır. Önceden verdiğimiz şu örneğe bir bakalım tekrar:

#!/usr/bin/env python
#-*- coding:latin-1 -*-
def matematik_toplama():
	global soru, soru2
	soru = input("Lütfen bir sayı girin: ")
	soru2 = input("Lütfen başka bir sayı daha girin: ")
	print "Bu iki sayı toplanırsa şu çıkar:"
	print soru + soru2
matematik_toplama()
 
def matematik_carpma():
	return
	print "bu iki sayı çarpılırsa şu çıkar:"
	print soru * soru2
matematik_carpma() 

Gördüğünüz gibi ikinci fonksiyonda "return" ifadesi kullanarak bu kısmın çalıştırılmasına engel olduk.

"pass" ifadesi

Şu örneğe bir bakalım:

#!/usr/bin/python
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.


Önceki Bölüm: Listeler, Demetler, Sözlükler
Sonraki Bölüm: Modüller

Bu yazı Programlama bölümünün bir parçasıdır.