Altblümler

 
4. Daha Fazla Kontrol Akışı

Bir önceki bölümde tanıtılan while deyiminin yanında Python'da diğer programlama dillerinde de bulunan genel kontrol akışı deyimleri (bazı farklarla birlikte) vardır.

 
4.1 if Deyimi

Belki de en iyi bilinen deyim türü if deyimidir. Örnek:

>>> x = int(raw_input("Lütfen bir sayı girin: "))
>>> if x < 0:
...      x = 0
...      print 'Negatif sayı sıfırlandı'
... elif x == 0:
...      print 'Sıfır'
... elif x == 1:
...      print 'Bir'
... else:
...      print 'Birden büyük'
...

Sıfır veya daha fazla elif kısımları olabilir, ve else kısmı seçimliktir. `elif' deyimi `else if' deyiminin kısaltılmışıdır ve aşırı girintileri engellemesi açısından faydalıdır. Bir if ... elif ... elif ... deyimleri dizisi diğer dillerde bulunan switch veya case deyimlerinin yerine kullanılabilir.

 
4.2 for Deyimi

for deyimi Pascal veya C dillerinde görülenden biraz farklıdır. Python'daki for deyimi herhangi bir sıranın ( liste, karakter dizisi vs.) elemanları üzerinde sırayla yinelenir. Örnek:

>>> # Bazı karakter dizilerinin boylarını ölçelim:
... a = ['kedi', 'pencere', 'kertenkele']
>>> for x in a:
...     print x, len(x)
...
kedi 4
pencere 7
kertenkele 10

Üzerinde yinelenilen sırada değişiklik yapmak güvenli değildir (bu sadece listelerde olabilir). Eğer böyle bir şey yapacaksanız bu iş için dilim gösterimi ile listenin bir kopyasını kullanabilirsiniz:

>>> for x in a[:]: # tüm listenin bir kopyasını oluştur
... if len(x) > 8: a.insert(0, x)
...
>>> a
['kertenkele', 'kedi', 'pencere', 'kertenkele']

 
4.3 range() Fonksiyonu

Eğer bir sayı sırası üzerinde tekrarlamalar yapmak isterseniz, belirli bir sıraya göre üretilen sayılardan oluşan bir liste yaratan range() yerleşik fonksiyonunu kullanabilirsiniz. Örnek:

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Verilen bitiş noktası asla üretilen listenin bir parçası olmaz; range(10) ifadesi 10 elemanı olan bir liste oluşturur. Listenin başlayacağı sayıyı ve artış miktarını da belirlemek mümkündür. Artış miktarı negatif de olabilir.

>>> range(5, 10)
[5, 6, 7, 8, 9]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]

range() ve len() fonksiyonlarını bir arada kullanarak da bir listenin elemanları üzerinde döngüler kurabilirsiniz:

>>> a = ['Python', 'programlama', 'öğrenmek', 'çok', 'kolay !']
>>> for i in range(len(a)):
...     print i, a[i]
...
0 Python
1 programlama
2 öğrenmek
3 çok
4 kolay

 
4.4 Döngülerde break, continue ve else

break deyimi, C'de olduğu gibi, içinde kaldığı en küçük for veya while döngüsünden çıkılmasına ve döngü deyiminin tamamen sona ermesine neden olur.

continue deyimi döngü içindeki diğer deyimlerin atlanıp bir sonraki yineleme işleminin başlamasına sebep olur.

Döngülerde else ifadesi de kullanılabilir; else öbeği döngü bittiğinde ( for için ) veya devamlılık koşulu geçersiz olduğunda ( while için ) işletilir; fakat döngü break deyimi ile sona erdiyse işletilmez. Bunu asal sayılar bulan aşağıdaki örnekte görebilirsiniz:

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...            print n, 'asal sayı değil. çarpanlar:', x, '*', n/x
...            break
...     else:
...          # çarpan bulunmadan döngü biter ise
...          print n, 'asal sayıdır'
...
2 asal sayıdır
3 asal sayıdır
4 asal sayı değil. çarpanlar: 2 * 2
5 asal sayıdır
6 asal sayı değil. çarpanlar: 2 * 3
7 asal sayıdır
8 asal sayı değil. çarpanlar: 2 * 4
9 asal sayı değil. çarpanlar: 3 * 3

 
4.5 pass Deyimi

pass deyimi hiçbir şey yapmaz. Python sözdizim kuralarına göre bir ifadenin gerekli olduğu, fakat programın bir şey yapması gerekmediği zaman kullanılabilir:

>>> while True:
...       pass # klavyeden CTRL+C ile kesilene kadar sürer
...

 
4.6 Fonksiyon Tanımlama

Herhangi bir değere kadar Fibonacci serisi yazan bir fonksiyon yaratalım:

>>> def fib(n):     # n'e kadar Fibonacci serisini yazdır
...     "n'e kadar Fibonacci serisini yazdır"
...     a, b = 0, 1
...     while b < n:
...         print b,
...         a, b = b, a+b
...
>>> # Tanımladığımız fonksiyonu çağıralım:
... fib(2000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

def anahtar kelimesi bir fonksiyon tanımını başlatır. Bu deyimden sonra bir fonksiyon adı ve parantez içinde parametreler yazılır. Fonksiyonun gövdesini oluşturan program satırları sonraki satırdan girintili olarak yazılırlar. Fonksiyon gövdesinin ilk satırı bir karakter dizisi de olabilir; bu karakter dizisi fonksiyonun belgelenmesinde kullanılır (docstring). Fonksiyonların belgelenmesinde kullanılan karakter dizilerini (docstring) otomatik olarak on-line ya da basılı belgeler oluşturmak için kullanan yazılımlar vardır. Ayrıca bazı geliştirme ortamları bunları program yazarken kolaylık sağlaması için etkileşimli olarak programcıya sunarlar. Yazdığınız fonksiyonlara bunları eklemeyi bir alışkanlık haline getirmeniz faydalı olur.

Fonksiyonların belgelenmesinde kullanılan karakter dizilerini ( docstring) otomatik olarak on-line ya da basılı belgeler oluşturmak için kullanan yazılımlar vardır. Ayrıca bazı geliştirme ortamları bunları program yazarken kolaylık sağlaması için etkileşimli olarak programcıya sunarlar. Yazdığınız fonksiyonlara bunları eklemeyi bir alışkanlık haline getirmeniz faydalı olur.

Bir fonksiyonun çağırılması (çalıştırılması) bu fonksiyondaki yerel (local) değişkenlerin olduğu bir simge tablosu oluşturur. Fonksiyon içerisinde bütün değer atama işlemlerinde değerler yerel simge tablosuna kaydedilir. Bir değişkene değinilmesi (reference) durumunda ise önce yerel, sonra global, ve en son yerleşik ( built-in) simge tablosunda arama yapılır. Bu yüzden global değişkenlere doğrudan değer atama yapılamaz (eğer global ifadesi içinde kullanılmamışlar ise) ; ancak bunlara değinilebilir ( reference).

Fonksiyon çağırıldığında fonksiyonun parametreleri yerel simge tablosuna eklenirler; yani parametreler fonksiyona değer ile çağrı ( call by value) kullanılarak iletilirler (yani parametreye yapılan değişiklikler yereldir, çağıran fonksiyondaki argümanlarda bir değişme olmaz). 4.1

Bir fonksiyon başka bir fonksiyonu çağırdığında bu çağrı için yeni bir yerel simge tablosu oluşturulur

Bir fonksiyon tanımı fonksiyon adının yürürlükte olan simge tablosuna eklenmesine sebep olur. Fonksiyonun adı yourumlayıcı tarafından kullanıcı tanımlı fonksiyon veri tipi olarak tanınır. Bu değer başka bir isime atanabilir ve bu da bir fonksiyon olarak kullanılabilir. Bu genel bir isim değiştirme yolu olabilir:

>>> fib
<function object at 10042ed0>
>>> f = fib # f de fib fonksiyonu olur
>>> f(100)
1 1 2 3 5 8 13 21 34 55 89

fib in bir fonksiyon olmayıp bir yordam ( procedure ) olduğunu düşünebilirsiniz. Python'da yordamlar çağıran fonksiyona değer geri döndürmeyen fonksiyonlardır. Aslında yordamlar da bir değer geri döndürürler, ama bu sıkıcı bir konudur. Bu değere None denir ve yerleşik (built-in)bir değişkendir. Yorumlayıcı yazılacak tek değer bu ise normalde None yazmaz. Bunu görmeyi çok istiyorsanız şunu deneyin:

>>> print fib(0)
None

Fibonacci serisini yazdırmak yerine, bunu bir liste şeklinde geri döndüren fonksiyon yazmak basittir:

>>> def fib2(n): # n e kadar fibonacci serisi geri döndürür
...     " n e kadar fibonacci serisi içeren liste geri döndürür"
...     sonuc = []
...     a, b = 0, 1
...     while b < n:
...         sonuc.append(b)    # değeri listeye ekle
...         a, b = b, a+b
...     return sonuc
...
>>> f100 = fib2(100)    # fonksiyonu çağır
>>> f100                # sonucu yazdır
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

Bu örnekte de bazı yeni Python özelliklerini görüyoruz:

 
4.7 Fonksiyon Tanımları Üzerine Daha Fazla Bilgi

Değişken sayıda argüman alan fonksiyonlar tanımlamak da mümkündür. Bunun için kullanılan üç yöntem olup bunlar birleştirilerek kullanılabilir.

 
4.7.1 Argüman Değerlerini Önceden Belirleme

Fonksiyon argümanlarına varsayılan (default) değerler atamak da mümkündür. Böylece çağıran fonksiyon bu argümanları sağlamazsa bunlar önceden belirlenmiş varsayılan değerlerini alırlar. Örnek:

def onay_al(prompt, denemeler=4, sikayet='Evet veya hayır, lütfen !'):
    while True:
        ok = raw_input(prompt)
        if ok in ('e', 'evet'): return 1
        if ok in ('h', 'hayır'): return 0
        denemeler = denemeler - 1
        if denemeler < 0: raise IOError, 'kararsız kullanıcı'
        print sikayet

Bu fronksiyon onay_al('Programdan çıkmak istiyor musunuz ?') ya da onay_al('Dosyayı silmek istiyor musunuz ?', 2) şeklinde çağırılabilir.

Fonksiyonun varsayılan (default) parametreleri fonksiyonun tanımlandığı anda, o an yürürlükte olan etki alanı (scope) içinde değerlendirilirler. Yani:

i = 7

def f(arg=i):
    print arg

i = 6
f()

7 yazacaktır.

Önemli uyarı: Fonksiyonun varsayılan (default) parametreleri sadece bir defa değerlendirilirler. Bu durum parametrenin liste gibi değiştirilebilir bir nesne olduğu durumlarda farklılık yaratır. Örneğin aşağıdaki fonksiyon ard arda çağırıldığında argümanlarını biriktirir:

def f(a, L = []):
    L.append(a)
    return L
print f(1)
print f(2)
print f(3)

Bu şu çıktıyı verir:

[1]
[1, 2]
[1, 2, 3]

Eğer varsayılan (default) parametre değerlerinin birbirini izleyen çağrılarla paylaşılmasını istemiyorsanız yukarıdaki fonksiyonu şu şekilde yazabilirsiniz:

def f(a, L = None):
    if L is None:
        L = []
    L.append(a)
    return L

 
4.7.2 Anahtar Kelime Argümanlar

Fonksiyonlar "anahtar kelime = değer" şeklindeki anahtar kelimelerle de çağırılabililer. Örneğin şu fonksiyon:

def otomobil(yakit,  hareket=' uçar', model='Anadol'):
    print "Eğer", yakit, "koyarsan bu", model, hareket

aşağıdaki gibi çağırılabilir:

otomobil('roket yakıtı')
otomobil(hareket = 'dans eder', yakıt = 'zeytin yağı' )
otomobil('ispirto', model = 'Kartal')
otomobil('su','bozulur','Şahin')

Şu çağrılar ise hatalıdır:

otomobil()                           # gerekli argüman eksik
otomobil(yakıt = 'su','zeytin yağı') # anahtar kelimeden sonra gelen
                                     # anahtar kelime olmayan argüman
otomobil('mazot', yakit = 'benzin')  # aynı argüman için iki değer
otomobil(sehir = 'İzmir')            # bilinmeyen anahtar kelime

Genel olarak, argüman listesinin başında konuma bağlı argümanlar bulunur ve anahtar kelime argümanlar onları izler; anahtar kelime adları da fonksiyonun parametrelerinden seçilir. Parametrenin varsayılan (default) değerlerinin olup olmaması önemli değildir. Bir argüman birden fazla değer alamaz; konuma bağlı parametre isimleri aynı çağrıda anahtar kelime olarak kullanılamazlar. İşte bundan dolayı hatalı olan bir örnek:

>>> def function(a):
...     pass
...
>>> function(0, a=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: keyword parameter redefined

Eğer fonksiyon tanımındaki son parametre **isim şeklinde ise bu parametre adları herhangi bir parametre olmayan anahtar kelime şeklindeki argümanların bulunduğu bir sözlük olur. Bu *isim(bir sonraki kısmın konusu) şeklindeki bir paramtre ile de kullanılabilir, ki bu parametre listesi içinde bulunmayan konuma bağlı argümanları içeren bir demet ( daha sonra incelenecek bir veri tipidir) olur . *isim parametresi **isim parametresinden önce gelmelidir. Buna örnek fonksiyon:

def kasapdukkani(etCinsi,*argumanlar, **anahtarKelimeler):
    print "--", etCinsi, "var mi ?"
    print "-- Maalesef", etCinsi, "kalmadı."
    for arg in argumanlar:
        print arg
    print '-'*40
    anahtarlar = anahtarKelimeler.keys()
    anahtarlar.sort()
    for ak in anahtarlar:
        print ak, ':', anahtarKelimeler[ak]

Şu şekilde çağırılabilir :

 kasapdukkani('martı eti',"Çok lezzetli.",
           "Çok satılıyor.",
           musteri = 'Martı Murat',
           kasap = 'Dev İsmail')

ve doğal olarak şu çıktıyı verir:

-- martı eti var mi ?
-- Maalesef martı eti kalmadı.
Çok lezzetli.
Çok satılıyor.
----------------------------------------
kasap : Dev İsmail
musteri : Martı Murat

anahtarKelimeler isimli sözlüğün içeriği yazdırılmadan önce anahtar kelime isimleri listesinin sort() metodunun çağırıldığına dikkat edin; bu yapılmaz ise argümanların hangi sıra ile yazılacağı tanımlanmamıştır.

 
4.7.3 Keyfi Argüman Listeleri

Son olarak, en ender kullanılan seçenek de keyfi sayıdaki argümanla çağırılabilen bir fonksiyon tanımlamaktır. Bu argümanlar bir demet ( değişmez liste [tuple]) içine alınırlar. Keyfi argüman listesinden önce sıfır ya da daha fazla normal argüman bulunabilir. Örnek:

def fprintf(file, format, *args):
    file.write(format % args)

 
4.7.4 Lambda Formundaki Fonksiyonlar

Yoğun istek üzerine fonksiyonel dillerde ve Lisp'te bulunan bazı özellikler Python'a eklenmiştir. lambda anahtar kelimesi ile küçük anonim fonksiyonlar yaratılabilir. İşte iki argümanının toplamını geri döndüren bir fonksiyon: "lambda a, b: a+b". Lambda fonksiyonları bir fonksiyon nesnesine ihtiyaç duyulan her yerde kullanılabilirler. Sözdizim (syntax) açısından bunlar tek bir ifade ile sınırlandırılmışlardır. Anlambilim (semantic) açısından ise normal fonksiyon tanımlamasına getirilen bir sözdizim güzelliğidir. İç içe tanımlanmış fonksiyonlarda olduğu gibi,lambda fonksiyonları kendilerini kapsayan etki alanindaki (scope) değişkenlere erişebilirler:

>>> def artirici_yap(n):
...     return lambda x: x + n
...
>>> f = artirici_yap(42)
>>> f(0)
42
>>> f(1)
43

 
4.7.5 Belgeleme Karakter Dizileri

Belgelemede kullanılan karakter dizilerinin şekli ve içeriği ile ilgili şartlar yeni yeni oluşmaktadır.

İlk satır daima nesnenin amacının kısa ve öz tanımı olmalıdır. Kısa olması için, nesnenin adından ve türünden bahsedilmemeli; zira bunlar başka yollarla da öğrenilebilir. Bu satır büyük harf ile başlayıp nokta ile bitmelidir.

Eğer belgeleme karakter dizisinde birden fazla satır var ise ikinci satır boş olup özet ile açıklamamın devamını birbirinden ayırmalıdır. Diğer satırlar bir ya da daha fazla satır olabilir. Bunlarla nesnenin özellikleri, çağrı şekilleri, yan etkileri vs. açıklanabilir.

Python ayrıştırıcısı (parser) çok satırlı karakter dizilerindeki girintileri yok etmez; yani belgeleri işleyen programlar gerekirse bunları atabilirler. ilk satırdan sonra gelen ve boş olmayan ilk satırdaki girinti miktarı belgeleme karakter dizisinin devamındaki girinti miktarını belirler. Bu girinti miktarına ``eşdeğer'' boşluk diğer satırların başından atılır. Daha az girintili satırlar olmamalı; ama olursa da bunların önündeki boşluğun tamamı atılmalı. Boşluğun eşdeğerliği tabların genişletilmesinden (1 tab 8 boşluğa) sonra sınanmalıdır.

İşte çok satırlı bir belgeleme karakter dizisi örneği:

>>> def benimFonksiyon():
...     """Sadece belgeler.
...
...     Başka birşey yapmaz. Gerçekten !.
...     """
...     pass
...
>>> print benimFonksiyon.__doc__
Sadece belgeler.

   Başka birşey yapmaz. Gerçekten !



Footnotes

... olmaz).4.1
Aslında nesne referansı ile çağrı daha iyi bir tanım olur, çünkü fonksiyona değiştirilebilir bir nesne geçirilirse çağıran çağırılanın o nesneye uyguladığı tüm değişiklikleri görür (listeye eklenen elemanlar gibi).