Eğlenceli bir programlama dili: Python

Özet

Python nesne yönelimli, fakat fonksiyonel ve yapısal programlama öğelerini de içerisinde barındıran "eğlenceli" bir programlama dilidir. Bu belgenin amacı okuyucuya Python'un eğlenceli dünyasının bir parçasını göstermektir.
Bu belge GNU Özgür Belgeleme Lisansı (GNU/FDL) altında serbestçe çoğaltılabilir.

1  Giriş

İnsanların ikilik kodu okumaya çalışarak gözlerini bozdukları karanlık çağların üzerinden çok zaman geçti. Bu süreç içinde önce Assembly, sonra C gibi dillerin ortaya çıkmasıyla program yazmak gitgide kolaylaştı. Bu sürecin günümüzde ulaştığı son nokta ise scripting dilleri. Her ne kadar ağır yük altında çalışacak programlar için hala C gibi diller tercih edilse de özellikle günlük işler için yazılan programlarda pratikliği açısından scripting dilleri öne çıkıyor. Python'da scripting dendiğinde Perl ve PHP ile birlikte ilk akla gelen dillerden biri.
Python ilk olarak 1990'ların başında Guido van Rossum tarafından ABC adlı bir dilin devamı olarak geliştirilmeye başlanmıştır. İlk olarak CWI bünyesinde geliştirilen Python daha sonra sırasıyla CNRI ve BeOpen Labs. bünyesinde geliştirilmiştir. Günümüzde ise geliştirilmesine Python Software Foundation tarafından devam edilmektedir. 1.6.1 sürümünden beri GPL uyumlu bir lisans olan Python Lisansı altında dağıtılmaktadır.

1.1  Neden Yılan?

Öncelikle şu yanlış anlamayı ortadan kaldıralım: Python dilinin ismi on metrelik bir yılandan gelmez. Gelse belki kimi insanlar tarafından karizmatik bulunabilirdi ancak bir dile insan yiyen bir sürüngenin adını vermek politik olarak doğru bir karar sayılmaz. Python adı dilin yaratıcısı Guido van Rossum tarafından BBC'nin ünlü komedi programı Monty Python'un bir bölümünü izlerken koyulmuştur. Guido van Rossum yılanları sever mi, orası bilinmez.

1.2  Neden Python?

Çünkü Python eğlencelidir. Python programcıya sağladığı kendine özgü kolaylıklarla kod yazmayı zevkli bir hale getirir. filter(), map() gibi fonksiyonlar ve list comprehensions (Liste Yorumları) gibi pratik özelliklerle diğer dillerdeki geleneksel kalıpların dışına çıkan programlar yazmanızı sağlar.
Aslında eğlenceli bir dil olması Python'u tercih etmek için başlı başına yeterli bir sebeptir. Ancak bunun yanında tabiiki Python'un diğer bazı belirleyici özelliklerini de gözardı etmemek gerekir. İleride daha detaylı bir şekilde değineceğimiz bu özelliklerden bazıları kısaca: Gelişmiş introspection sistemi, %100 nesne yönelimli yapı ve sadece kişisel kullanımda değil daha üst seviye sistemlerde de kendini kanıtlamış olması ve diğer programlama dilleri ile uyumlu çalışabilmesidir.

1.3  Python yorumlayıcısı

Python programlarını çalıştırabilmek için python yorumlayıcısına ihtiyacımız vardır. Genelde GNU/Linux ve BSD gibi özgür UNIX'ler ile hazır gelse de diğer işletim sistemleri için Python yorumlayıcısını http://www.python.org adresinden indirebilirsiniz. Yorumlayıcıyı çalıştırmak için UNIX sistemlerde komut satırında "python" yazmanız, Windows sistemlerde ise Başlat menüsünden "Python (command line)" seçeneğini seçmeniz yeterlidir. Bu interaktif olarak Python yorumlayıcısını kullanmanız için size bir komut satırı açacaktır. İlk açıldığında python komut satırı aşağı yukarı şöyle gözükür:
Python 2.3.2 (#2, Oct  6 2003, 08:02:06) 
[GCC 3.3.2 20030908 (Debian prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

İlerleyen sayfalardaki örnek kodları buraya elle yazarak çalıştırabilirsiniz. Yorumlayıcıdan çıkmak için
import sys
sys.exit()

yazmanız veya UNIX sistemlerde Ctrl+D tuşlarına basmanız yeterlidir. Yazının geri kalanında başında ">>>" karakterleri bulunan satırlar yorumlayıcıda interaktif olarak yazılan komutları ifade etmektedir.

2  Hello World!

Python her ne kadar bir script dili olsa da diğer scripting dillerinde olan bazı özellikleri içermez. Herşeyden önce Python'da küçük-büyük harf ayrımı mevcuttur. Bu nedenle foobar, fooBar ve FooBar birbirinden farklı nesnelerdir. Python'un bir diğer farkı ise sayısal ve metin tipleri arasında otomatik çevirme yapmamasıdır. Son olarak Python'da değişkenler kullanılmadan önce mutlaka ilklendirilmelidir (initialization). Python yorumlayıcısı değişkenlere kullanıldığı yere göre otomatik bir değer atamayacaktır. İlklendirilmemiş bir değeri kullanmaya kalktığınızda bir NameError ile karşılaşısınız. Ancak buna rağmen değişkenlerin tiplerinin herhangi bir özel yerde tanımlanması gerekmez, örneğin kirkiki=42 yazdığımızda kirkiki adlı değişken otomatik olarak integer veri tipine sahip olacaktır.
Son olarak akılda bulundurulması gereken bir detay Python'da herşeyin bir nesne olduğdur. Bu nedenle mesela bir değişkene atamadan doğrudan kullanacağımız bir string de bir string değişkenle aynı özelliklere sahiptir.
Birçok programcının bu iki kelimeyi yanyana görmekten nefret ettiğini biliyorum ama bu konuda yazanlar için de nasıl zevkli olduğunu tahmin bile edemezsiniz. İşte Python'ca Hello World!:
print "Hello Deep Thought!"

Tabiiki bu Python'un nasıl bir dil olduğu konusunda bir fikir vermiyor. Şu örnek biraz daha açıklayıcı olacaktır:
import os

if os.name == "posix":
print "Hello UNIX!"
elif os.name in ["nt", "ce"]:
from sys import stdout
stdout.write("Hello Microsoft!\n")
elif os.name == "mac":
helloto = "Steve Jobs"
print "Hello %s!"%helloto
else:
print "Pardon?"

3  Veri Tipleri

Python'da da diğer dillerdeki temel veri tipleriyle birlikte kendine özgü bazı veri tipleri bulunur. Python'un en büyük avantajlarından biri öntanımlı veri tiplerinin kolayca programcı tarafından tanımlanacak sınıflar tarafından taklit edilebilmesidir. __getattr__ ve __str__ gibi özel metodların yaratılan sınıf tarafından taklit edilmesi ile tamamen isteğe göre hazırlanmış özel veri tipleri üretilip diğer tüm veri türleri gibi kullanılabilir. Örneğin bu sayede string, integer ve listenin çeşitli özelliklerine sahip sınıflar üretilebilir. Bu özel fonksiyonların tam listesi Python Dil Rehberi'nde2 bulunabilir

3.1  Boolean değerler

Python'un geniş veri tipi seçenekleri arasında en yeni olanı boolean değerlerdir. Python 2.2'ye kadar True ve False anahtar kelimeleri yoktur. 2.2'de ise 0 ve 1 sayılarına denk olarak bu kelimeler getirildikten sonra sonunda 2.3 sürümü ile Python gerçek bir boolean tipine kavuşmuştur. Boolean veri tipinin Python'da bu kadar geç ortaya çıkmasının sebebi Python'un C'ye benzer bir şekilde her türlü veri tipini doğruluk testinde kullanabiliyor olmasıdır. Örneğin boş bir string, boş bir liste veya 0 sayısı yanlış, 0 dışındaki herhangi bir sayı, boyutu 0'dan büyük olan herhangi bir liste veya string ise doğru kabul edilecektir. Bunun dışında __nonzero__ adlı fonksiyonu kendi sınıfımızın içerisinde tanımlayarak kendi yaratacağımız bir sınıfı da doğruluk testinde kullanmak mümkündür.

3.2  Sayısal Tipler

Python'da dört temel sayısal veri tipi bulunmaktadır. Bunlar integer (Tamsayı), long (Uzun tamsayı), float (Kayar noktalı sayı), complex (Karmaşık sayı) olarak adlandırılırlar. Bu veri tiplerinin tamamı işaretli sayılardır. Gerektiği durumlarda Python yorumlayıcısı integer, long ve float tipleri arasında otomatik değişimler yapabilmektedir. Örneğin Python yorumlayıcısına integer'ın sınırlarını aşan bir sayı verdiğiniz takdirde yorumlayıcı bunu otomatik olarak long tipine çevirecektir. Aynı şekilde bir işlemin operandlarından birinin float olması halinde sonuç ta float şeklinde dönecektir.

3.3  String Tipleri

Python'da unicode desteği sonradan eklendiğinden string ve unicode verileri ayrı veri tipleri olarak tanımlanmıştır. Unicode nesneleri temelde string tipleri ile aynı özellikleri paylaşır ancak unicode kullanımına özgü bazı ek fonksiyonlara sahiptir. Unicode nesnelerini kullanırken unutulmaması gereken bir detay eğer nesne ASCII karakterlerinin dışında veri içerecekse unicode nesnesinin encode() fonksiyonunu kullanarak uygun karakter setine dönüştürülmesini sağlamaktır. Gerek string gerekse unicode nesneleri temelde bazı liste fonksiyonlarını ve dilimleme gibi bazı liste özelliklerini de destekler. Bir string ', " veya """ karakterlerinin arasına alınarak yazılabilir. Dikkat edilmesi gereken nokta sözkonusu string yazılmaya hangi karakter ile başlanmışsa aynı karakter ile bitirilmelidir. Örneğin "Ali'nin" geçerli bir yazım iken 'Ali "kırkiki" dedi" şeklinde bir yazım hatalıdır. Bir kısayol olarak unicode nesneleri yaratılacağında string operatörlerinin başına bir adet u harfi getirilerek doğrudan unicode nesneleri yaratılabilir. Buna göre "Kırkiki" bize normal bir string nesnesi u"Kırkiki" ise bir unicode nesnesi verecektir.
Python C printf tarzı metin biçimlendirme (String Formatting) karakterlerini destekler. Bu biçimlendirme karakterlerinin tam bir listesine http://www.python.org/doc/current/lib/typesseq-strings.html adresinden ulaşabilirsiniz. Bu tip metin biçimlendirme işlemlerinde Python'un getirdiği bir kolaylık biçimlenecek metnin içine koyulacak değerleri bir liste yerine sözlükten alabilme özelliğidir. Bu sayede biçimlendirilecek metnin içine yerleştirilecek veriler listedeki sıralarından bağımsız olarak isimleriyle kullanılabilirler. Örneğin:
>>> print "%d = %s"%(42,"Kırkiki") #Klasik biçimlendirme.
42 = Kırkiki #Elemanların sırası değiştirilemez.
>>> sozluk = {"sayi":42, "yazi":"Kırkiki"}
>>> print "%(yazi)s = %(sayi)d"%sozluk #Sözlük kulanarak biçimlendirme
Kırkiki = 42 #yaptığımızda daha sonra elemanların sırasını değiştirebiliriz.
>>>

3.4  Dizi Tipleri (Sequence Types)

Python tek bir dizi tipi yerine kendi içerisinde Tuple (tüp) ve List (liste) olmak üzere iki farklı veri tipi barındırır. Diğer tüm veri tipleri gibi Bu tiplerde programcının oluşturacağı sınıflar tarafından taklit edilebilirler. Tüp tipindeki verilerin en büyük özelliği içerdiği verilerin değiştirilmesinin mümkün olmamasıdır. Buna karşılık Liste tipindeki veriler diğer dillerden bildiğimiz dizi tipindeki veriler ile aynı özellikleri gösterirler. Python dizi tiplerinin diğer dillerdeki benzer tiplerden en önemli farkı negatif indeksler ve dizi dilimlemeleridir (slicing). Negatif indeksler sayesinde dizi elamanlarına alışıldık 0'dan - 1'e kadar olan sayılarla erişim dışında dizinin sonundan başlayarak negatif sayılarla da erişebiliriz. Dizinin son elemanı -1 olmak üzere başa doğru gidildikçe küçülen negatif sayılarla dizinin diğer elemanlarına erişebiliriz. Buna göre dizi[-1] bize dizinin son elemanını verirken dizi[-2] sondan ikinci elemanı verecektir. Bu özellik Python'un dizi dilimleme yetenekleri ile birleştirildiğinde bize dizilerin belirli bölümlerini ayıklamak konusunda oldukça güçlü bir araç sunar.
Dizi dilimleme dizi veya dizi-benzeri bir veri tipindeki verilerin belirli bir bölümünü almamızı sağlar. Dilimler başlangıç ve bitiş indeksleri verilerek diziden alınır. Dizi dilimlemek için olağan dizi erişim şekli olan dizi[indeks] yazımı yerine dizi[başlangıç indeksi:bitiş indeksi] şeklinde bir yazım kullanmak gerekir. Bu şekilde aldığımız bölüm dizinin belirttiğimiz indekse sahip elemanlarının arasındaki elemanların bir kopyası olacaktır. Başlangıç indeksinin verilmemesi durumunda dizinin başından bitiş indeksine kadar, bitiş indeksinin verilmemesi durumunda ise başlangıç indeksinden dizinin sonuna kadar olan bölüm alınacaktır. Bu durumu birkaç örnekle açıklamak gerekirse:
>>> dizi = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> dizi[-3] #Negatif indeks dizinin son elmanını döndürür
7
>>> dizi[3:8] #Dizinin üçüncü ile sekizinci elemanları arasındaki bölümü döndürür
[3, 4, 5, 6, 7]
>>> dizi[3:-2] #Dizinin üçüncü ile sondan ikinci elemanları arasındaki bölümü döndür
[3, 4, 5, 6, 7]
>>> dizi[:4] #Dizinin ilk dört elemanını döndürür
[0, 1, 2, 3]
>>> dizi[4:] #Dizinin dördüncüden sonraki elemanlarını döndürür
[4, 5, 6, 7, 8, 9]
>>> dizi[:] #Dizinin bir kopyasını döndürür
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

3.5  Eşleştirme Tiperi (Mapping Types)

Python öntanımlı olarak sadece bir temel eşleştirme tipi ile gelir: Sözlük (Dictionary). Eşleştirme tipleri anahtar:veri şeklindeki veri yapılarını saklamak için kullanılırlar. Eşleştirme tipleri yapı olarak dizi tiplerine benzese de dizilerin indekslerinin aksine eşleştirme tiplerinin anahtarları sıralı değildir. Anahtarlar hemen hemen her tipteki veriden karışık şekilde oluşabilir ancak tek kural anahtar olacak verilerin değişmez (immutable) bir tipte olmasıdır. Örneğin tüpler, stringler ve sayısal tipler anahtar olabilirken değişken bir tip olan listenin anahtar olması mümkün değildir. Veri kısmı içinse bu tip bir kısıtlama mevcut değildir.
Bir sözlük yaratmanın en kolay yolu anahtar, veri ikililerini süslü parantezlerin ("{" ve "}" karakterleri) içerisine yazmaktır. Örneğin:
sozluk = {42:'Kırkiki', '00101010':'foobar'}

3.6  None Nesnesi

None nesnesi C'deki NULL veya Pascal'daki Nil değerinin Python'daki benzeridir. Varolmayan değerleri ifade etmekte kullanılan None nesnesinin doğruluk değeri yanlış'a denktir.

4  Sözdizimi

Python sözdizimi olarak bazı dillerle benzerlikler içermekle birlikte özellikle C sözdizimini andıran Perl ve PHP gibi dillerden oldukça farklıdır. Temel sözdizimi öğeleri şu şekilde sıralanabilir:

4.1  Bloklar

Python'un sözdiziminin diğer dillerle farkının en çok ortaya çıktığı nokta blok yapılarıdır. Diğer dillerde {} karakterleri veya begin, end gibi işaretlerle ile sağlanan blok yapıları Python'da girinti-çıkıntılar yardımıyla sağlanır. Kodun içerisinde aynı seviyede girintiye sahip olan alt alta bölümler aynı blok içerisinde kabul edilir. Hello World'e dönecek olursak if bölümünden sonra alt satırlardaki komutların eşit oranda girintiye sahip olmasının sebebi göze güzel gözükmekten öte, bloklamayı sağlamaktır. Kodunuzda girinti/çıkıntıları doğru ayarlamadığınız takdirde Python kodunuz çalışmayacaktır.
Blok yapılarının girinti çıkıntılarla sağlanması ilk başta itici gelebilir. Sonuçta diğer dillerdeki gibi belirli ifadeler ile bloklama yapıldığında bloklar daha kesin olarak belirlenebilir diye bir düşünce mevcuttur. Tabiiki blokların başlangıç ve sonunu belirli karakterlerle belirlemenin kendine özgü avantajları vardır. Örneğin tüm bir blok bu sayede tek satıra yazılabilir ancak bu durum kodun okunabilirliğini azalatacaktır. Hangi dil kullanılırsa kullanılsın kod yazarken okunabilirliği ön planda tutmak her zaman içi önemlidir. Kodu okunabilir kılmak için de girinti/çıkıntıları doğru kullanmak zaten bir programcılık geleneğidir. Tabiiki pek çok gelenek gibi bu da programcılar tarafından pek umursanmaz ve ortaya sahibinin dahi okuyunca anlamayacağı kodlar çıkar Bu aşamada Python programcıyı düzenli kod yazmaya zorlayarak hem bloklar için fazladan karakterler kullanma ihtiyacını ortadan kaldırır hem de kodun düzenli kalmasını sağlar. Tabiiki bir insan spagetti kod yazmak isterse her dilde yazar. Fakat normal koşullar altında bu zorlamalar kodu düzenli tutmak için yeterli olacaktır.

4.2  Kontrol Yapıları

Bir dilin bel kemiği şüphesiz ki kontrol yapılarıdır. İf-Else tarzı denetleme deyimleri ve for, while gibi döngüler her dilde bulunsa da aynı parmak izi gibi dilden dile bazı farklılıklar içerirler. Python'da her programlama dili gibi bu yapıları bünyesinde bulundurur. Bu yapıların genel yapısı şu şekildedir:
	  :
<çalıştırılacak komut>

Python'daki denetleme deyimleri ve döngüler diğer dillerdekinden daha farklı olmadığıdan burada tekrar tümünü anlatmanın gereği yoktur. Fakat diğer dilerdeki benzerlerinden bazı farklılıklar gösteren for ve while deyimlerinin bu farklarına bir değinmekte fayda var.
C ve Pascal gibi dillerde for deyimi sayı sayma esasına dayanır. Sayı tipinde bir değişken artırılıp azaltılarak kontrol sistemi kurulur. Python'da ise for döngüsü bir liste üzerinde işletilerek listenin her elemanı listedeki sıralarına göre işleme alınır. Örneğin:
liste = ["42","00101010","*"]
for eleman in liste:
print eleman

For döngüsü her ne kadar bir liste üzerinde çalışsa da kimi zaman doğrudan sayılar üzerinde çalışmamız gerekebilir. Böyle bir durumda sayılardan oluşan bir listeyi her seferinde elle yazmak tabiiki mantıklı olmayacaktır. Python böyle durumlar için bize range() fonksiyonunu sunar. Bu fonksiyon kendisine verdiğimiz parametrelere göre bize bir sayı listesi üretir. range() fonksiyonu üç farklı parametre alır: taban sayı, tavan sayı ve artırma miktarı. Bu her ne kadar bize C'nin esnekliğini sunmasa da istediğimiz sayıları elde etmek için yeterlidir. Taban sayı ve artırma miktarı parametreleri kullanılmayabilir, bu durumda başlangıç olarak 0 ve artırma miktarı olarak ta 1 alınır. Gözönünde bulundurulması gereken bir faktör liste oluşturulurken tavan sayısının listeye dahil edilmediğidir. Örnek vermek gerekirse:
	>>> range(10) #0'dan 10'a kadar (10 hariç) olan sayıları döndür
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1, 11, 2) #11'den küçük pozitif tek tamsayıları döndür
[1, 3, 5, 7, 9]

Python'da benzerlerinden farklılık gösteren diğer bir deyim ise if deyimidir. Python'da case veya switch gibi ayrı bir kalıp bulunmadığından if deyimi bu fonksiyonaliteyi sağlayacak şekilde düzenlemiştir. Bir if deyiminin içerisinde kullanacağınız birden fazla elif (evet Else-if'in kısaltması) deyimi ile farklı koşulları test etmek mümkündür. Hello World uygulamasındaki işletim sistemi karşılaştırmasında bu durumun tipik bir örneğini görmek mümkündür.

4.3  Fonksiyon ve Sınıf Tanımlamaları

Python'da fonksiyon tanımlamaları def anahtar sözcüğü ile yapılır. genel yapı def (): şeklindedir. Fonksiyonun kendisi bu tanımın altındaki satırlara uygun girinti ile yazılır. Fonksiyon parametrelerini tanımlarken duruma göre bazı farklı yaklaşımlar kullanmamız mümkündür. Tanımladığımız fonksiyon parametrelerinin bazılarına öntanımlı değerler atamamız mümkündür. Bu sayede fonksiyonu çağırırken yalnızca öntanımlı değeri değiştirmemiz gereken durumlarda o parametreye müdahale etmemiz gerekecektir. Parametrelere öntanımlı değer atanması şu şekilde yapılır:
	   def foobar(foo="bar"):
...

Bu durumda Python yorumlayıcısı fonksiyonu sadece foobar() şeklinde çağırdığımızda foo değişkenine otomatik olarak bar değerini atayacaktır. Parametrelere öntanımlı değer atarken dikkat edilmesi gereken önemli bir nokta öntanımlı değer atanan parametrelerin, atanmayan parametrelerden sonra gelmesi gerektiğidir.
Python'un fonksiyon tanımlarında içerdiği en önemli kolaylık değişken uzunluktaki parametre listeleridir. Bu sayede bir fonksiyonun sınırsız sayıda parametre alması sağlanabildiği gibi bir tüp, liste veya sözlük içerisindeki veriler de kolayca bir fonksiyona parametre olarak geçirilebilir. Değişken uzunlukta parametreler alan bir fonksiyon tanımı şu şekilde yapılır:
	    def foobar(*args, **kwargs):
...

Bu şekilde tanımlanan bir fonksiyona geçirilen parametrelere fonksiyonun içinde args adlı bir tüpü ve kwargs adlı bir sözlüğü kullanarak erişebiliriz. Bu isimleri kullanmak mecburi olmadığı gibi bu iki parametre tipi aynı anda kullanılmayıp arı ayrı da kullanılabilir. Fakat bu kullanım tarzı genel olarak uygulamada yerleşmiştir. Ancak eğer ikisini bir arada kullanacaksak mutlaka önce *args sonra **kwargs tanımlarını kullanmamız gerekir.
Bu iki çağrı tipini birleştirerek fonksiyon tanımları yamamız da tabiiki mümkündür. Bu durumda dikkat etmemiz gereken kural parametrelerin sıraının önce normal parametreler, ardından öntanımlı değere sahip parametreler, ardından geri kalan parametreleri toplamak üzere *args ve **kwargs tanımlarını kullanmaktır. Aksi halde Python yazım hatasından şikayet edecektir. Örnek bir fonksiyon tanımı şu şekilde yapılabilir:
	   def foobar(foo, bar="42", *args, **kwargs):
...

Sınıf tanımlamaları class (ne süpriz ama) anahtar sözcüğü ile yapılır. Bir sınıf tanımlaması şu şekilde yapılır: class (, ,...):Eğer sınıfımız bir temel sınıf'tan (base class) türetilmiyorsa parantezleri kullamamaya dikkat etmemiz gerekir. Bir sınıfın tanımında birden çok temel sınıf kullanmak mümkündür, bu sayede Python'da nesne yönelimli programlamanın güzelliklerinden çoklu miras almayı (multiple inheritance) kullanmamız mümkün hale gelir.
Bir sınıf içerisindeki fonksiyonları tanımlarken ilk parametre fonksiyonun çağrıldığı sınıf örneğine (instance) referans veren self parametresi olmalıdır. Parametresi olmayan fonksiyonları tanımlarken dahi bu parametrenin parametre listesinin ilk elemanı olarak eklenmesi gerekir. Bu parametrenin adının self olması zorunlu olmamakla birlikte uygulamada bu isim yerleşmiştir. Hello adlı bir fonksiyona sahip bir sınıf aşağıdaki gibi gözükecektir:
	    class HelloWorld:
def Hello(self):
print "Hello Python!"

Python yorumlayıcısı bu fonksiyonu çağırırken self parametresini otomatik olarak yerleştirecektir. Bu nedenle HelloWorld sınıfının KirkIki adı örneğindeki Hello fonksiyonunu çağırmak istediğimizde KirkIki.Hello() yazmamız yeterli olacaktır.

4.4  İstisnalar (Exceptions)

Bir büyüğümüzün de dediği gibi: "Yakalanmayan istisnalar, kaideyi bozar". Python pek çok modern dil gibi hata yakalamanın pratik bir yolu olan istisna sistemine sahiptir. İstisnalar Pascal'a benzer şekilde try ... except blokları ile yakalanır ve raise ile ortaya çıkarılırlar.
try anahtar sözcüğü ile başlayan blokların sonunda except anahtar sözcüğü ile bir veya daha fazla hatayı yakalamak mümkündür. Tipik bir try ... except bloğu şu şekilde olacaktır:
try:
foobar() #Olmayan bir fonksiyonu çağırmaya çalış

except NameError, isim:
"""
Eğer bir NameError oluşursa beraberinde döndürdüğü
detayları isim değişkenine al
"""
print isim, 'adı tanımlı değil'
"""
NameError'a ilişkin
bir hata mesajı görüntüle
"""

except (TypeError, ValueError): #TypeError veya ValueError oluşursa yakala
print "Geçersiz değer" #ve hata mesajı göster

except: #Geri kalan istisnalarda bir hata mesajı göster
print "Beklenmeyen istisna"
raise #Yakalanan istisnayı daha üst seviyelerden yakalanabilmesi için yükselt.

else: #Hiçbir hata oluşmazsa başarı mesajını görüntüle
print "Hiçbir sorun oluşmadan program tamamlandı"

Bu örnekte Python'a özgü bir anahtar sözcük olan else karşımıza çıkmaktadır. Hiçbir istisna oluşmadan programın tamamlanması halinde else bloğundaki kodlar çalıştırılacaktır. Herhangi bir istisna oluşması halinde ise else bölümü çalıştırılmayacaktır. Bu konuyla ilgili son anahtar sözcük ise bffinally sözcüğüdür. finally sözcüğü bir hata oluşsun yada oluşmasın mutlaka çalıştırılması gereken kritik kısımları belirlemekte kullanılır. Bu bölümde genelde açık dosyaların kapatılması, ağ bağlantılarının kesilmesi gibi işlemler yürütülür. Bir try bloğunun içerisinde aynı anda hem except hem de finally sözcükleri bir arada bulunamaz. Ancak içiçe try blokları kullanarak bunun üstesinden gelmek mümkündür. Örneğin:
try:
try:
...
Sorun çıkarabilecek işlemler
...

except:
...
Hata yakalama işlemleri
...

finally:
...
Her durumda çalıştırılacak kodlar
...

4.5  Diğer Anahtar Sözcükler

4.5.1  import

import anahtar sözcüğü diğer Python modüllerindeki fonksiyon ve sınıfları kendi programımıza dahil etmemizi sağlar. Bu niteliği ile C'deki include veya Pascal'daki uses anahtar sözcükleri ile benzerlik gösterse de birçok yönden onlardan daha gelişmiş bir yapıya sahiptir. import sözcüğü ile bir modülün tamamını veya içerisindeki bazı fonksiyon ve sınıfları programımıza dahil etmemiz mümkündür. Bunu from import şeklinde yapabiliriz. import sözcüğü ile bir seferde birden fazla modülü veya nesneyi de virgülle ayırarak kodumuza dahil etmemiz mümkündür. import komutunun her zaman kodumuzun başında olması mecburi olmadığı gibi bir test ifadesinin ortasında bulunarak koşullu olarak kodumuza dahil edilmesi sağlanabilir. import komutunun bir fonksiyonun içinde bulunması durumunda ise dahil edilen modül sadece o fonksiyonun içerisinden erişilebilir durumda olacaktır.

4.5.2  break ve continue

break ve continue sözcükleri döngülerin içerisinde anlam ifade ederler. break sözcüğü döngüyü kesip programın akışını döngünün bittiği satırdan devam ettirir. continue deyimi ise o anda işlenmekte olan eleman için döngüyü keserek döngünün ilk satırından tekrar işletir. Bunu örnek üzerinde incelemek daha açıklayıcı olacaktır.
>>> i = 0
>>> while 1: #sonsuz bir döngü kur
... i += 1
... if i == 5:
... continue
... if i == 10:
... break
... print i
...
1
2
3
4
6
7
8
9
>>> print i
10
>>>

4.5.3  return

Bir fonksiyondan bir değer döndürerek çıkmak gerektiğinde return anahtar sözcüğü kullanılır. Bir fonksiyonun her zaman bir değer döndürmesi mecburi değildir, bir return komutu bulumaması halinde öntanımlı olarak None nesnesini döndürür. return sözcüğüne rastlanan yerde fonksiyonun işleyişi kesilir ve fonksiyonu çağıran kod kaldığı yerden devam eder. Döndürülecek değerleri virgülle ayırarak bir return komutuyla birden çok değerin bir seferde döndürülmesi mümkündür.

4.5.4  pass

Hiçbirşey yapılmamasını söyleyen bir anahtar sözcüktür. Python yorumlayıcısı bunu gördüğünde "burada görülecek birşey yok, devam et" der. Bir fonksiyon veya sınıfın sadece tanımının yapılıp gerçek bir kod yazılmayacağı durumlarda tanım satırının altına sadece pass yazılması yorumlayıcının o sınıf veya fonksiyon varmış gibi tanımlamasını, fakat sınıf veya fonksiyon çağrıldığında hiçbir iş yapmamasını sağlar.

4.5.5  Yorum Satırları

İyi kod yazmanın en önemli kurallarından biri kodun içinde mümkün olduğunca açıklayıcı yorum satırları yazmaktır. Python'da iki tip yorum satırı mevcuttur. Tek satırlık yorumlar # karakteri ile başlarlar. Birden fazla satıra sahip yorumlar ise """ karakterleri ile başlayıp aynı şekilde kapanırlar. """ karakterleri ile başlayan yorumların bir diğer özelliği ise sınıf veya fonksiyon tanımlarının hemen altına yazıldıklarında "docstring" olarak ta adlandırılan dökümantasyon metni olarak algılanmalarıdır.
Dökümantasyon metinleri o sırada tanımlanan sınıf veya fonksiyon hakkında bilgi içeren metinlerdir. Hemen hemen her Python nesnesinin __doc__ adlı özel bir niteliği (Special Attribute) bulunur. Bu nitelik o sınıf veya fonksiyonun dökümantasyon metnini içerir. Bu sayede interaktif yorumlayıcı içerisinde bir fonksiyon veya sınıf hakında bilgi almak için .__doc__ yazmamız yeterlidir. Bu durum şu örnekle daha iyi açıklanabilir:
>>> def foobar(foo=None):
... """
... Hiçbir iş yapmayan bir fonksiyon,
... öntanımlı olarak None'a eşit olan bir de
... parametresi var
...
... """
... pass
...
>>> print foobar.__doc__

Hiçbir iş yapmayan bir fonksiyon,
öntanımlı olarak None'a eşit olan bir de
parametresi var


>>>

Bu dökümantasyon metinleri happydoc gibi belgelendirme sistemleri tarafından kullanıldığı gibi IDLE gibi gelişmiş interaktif yorumlayıcı arayüzleri tarafından da anında yardım sağlama amacıyla kullanılır. Yorum yazarken uyulması mecburi olmamakla birlikte gözönünde bulundurulması tavsiye edilen bazı şekil kuralları Python Stil Rehberi'nde3 tanımlanmıştır. Uygun krallar dahilinde yazıldığında yorum satırlarının programınızın birim testi olarak kullanılması dahi mümkündür.

5  Peki ama neden Python?

Buraya kadar Python'un dil yapısını anlattık, güzel hoş ama asıl önemli noktaya şu ana kadar değinmedik. Bu Python'un eğlenceli yanı neresi? Python'u eğlenceli yapan bir program yazarken sürekli olarak karşılaştığımız bazı ufak tefek problemlerin çözümüne getiriği farklı yaklaşımdır. Şimdi bu yaklaşımın bize sağladığı güzellikleri bir inceleyelim.

5.1  List Comprehensions (Liste Yorumlama)

Liste yorumlama (ne yazık ki tam ve anlamlı bir türkçe karşılık bulamadım) Python'un belki de en farklı özelliklerinden biridir. Liste türü veriler üzerinde pratik olarak filtreleme düzenleme yapmamızı sağlar. Örneğin sıradan bir programlama mantığıyla bir sayılardan oluşan bir listenin belirli koşullara uyan elemanlarını bir işleme tabi tutmak istediğimizde (örneğin sayılardan oluşan bir listenin tek sayı elemanlarının karesini almak istersek) yazacağımız kod aşağı yukarı şöyle olacaktır:
kare_listesi = []
"""
Unutmayın, Python'da değişkenler kullanılmadan önce
ilklendirilmelidir (Initialization).
"""

for sayi in range(10):
if sayi % 2:
"""
Sayı ikiye tam olarak bölünmezse tek sayıdır, 1 döndürür.
"""
kare_listesi.append((sayi,sayi**2))
#**operatörü sayının belirtilen kuvvetini döndürür.

print kare_listesi

Aynı sorunu liste yorumlama kullanarak çözdüğümüzde ise tüm iş tek satırda halledilir:
kare_listesi = [(sayi, sayi**2) for sayi in range(10) if sayi%2]
print kare_listesi

Şimdi bu kodu parçalayalım. Daha soyut bir gösterimle liste yorumlama şu şekilde tanımlanabilir:
for in if
İlk bölüm değişkene uygulanacak işlemi tanımlar. Bu bölümde standart Python operatörlerinin yanında kendi tanımlayacağımız bir fonksiyonu da kullanmak mümkündür. Liste yorumu sonucunda birden fazla değer döndürmek te mümkündür. Bu durumda döndüreceğimiz değerleri parantezlerin içine alarak bir tüp haline getirmemiz gerekir. Örneğimizde sayının kendisi ve karesi parantezlerin içine alınarak bir tüp oluşturacak şekilde döndürülmektedir.
İkinci bölüm for anahtar sözcüğü yardımıyla üzerinde işlem yapacağımız listeyi tanımlar. Burada da normal bir liste, bir tüp veya listeleri taklit eden kendine özgü bir veri tipi kullanmamız mümkündür. Aynen sıradan bir for döngüsünde olduğu gibi listemizin elemanları sırayla değişkene atanır.
Üçüncü bölüm ise her liste yorumlama işleminde bulunması mecburi olmayan test bölümüdür. Bu bölüme yazacağımız ifade ile listeyi belirli bir koşula göre filtrelememiz mümkündür. Buraya da diğer bölümlerde olduğu gibi bir python ifadesi veya fonksiyonu yazabiliriz. Fonksiyonun veya ifadenin döndürdüğü değerin Python tarafından tanımlanan doğruluk değerine ("", 0, None ve () gibi ifadeler için yanlış geri kalan çoğu ifade için doğru değeri kabul edilmiştir) göre liste elemanı ilk aşamadaki işleme sokulup, sonuç olarak döndürülür veya döndürülmez.
İlk bakışta tuhaf gözükse de liste yorumlama işlemi hem döngülerinizde daha sadece ve okunabilir bir görünüm elde etmenizi sağlayacak, hem de kodunuzu daha modüler bir şekle sokmanız yönünde sizi zorlayacaktır.

5.2  Çoklu Atama (Multiple Assignments)

Fonksiyon tanımları bölümünde gördüğümüz gibi Python fonksiyonları bazen birden fazla değer döndürebilir. Bu durumda fonksiyonun tü çıktısını tek bir değişkene atayarak çıktıyı bir tüp şeklinde kullanabileceğimiz gibi çoklu atama yöntemiyle çıktının her bir elemanını ayrı bir değişkene de atamamız mümkündür. Özellikle birden fazla sonuç döndüren ve sonuçların kendilerinin de bir liste yapısı oluşturduğu !getopt! gibi kütüphaneleri kullanırken bu yönteme başvurmak neredeyse mecburiyettir. Çoklu atama, atama operatörünün (=) iki tarafına da virgülle ayrılmış şekilde birden fazla değer yazarak yapılır. Örneğin:
a, b, c = 1, 2, 3

Tabiiki değerler her zaman elle yazılmış olmak zorunda değildir. Örneğin bir programın stanard girdi, standart çıktı ve standart hata çıktılarını programımızdaki değişkenlere atamamızı sağlayan popen3 komutunun döndürdüğü 3 ayrı değişkeni kodumuzdaki 3 ayrı değişkene atamak için de bu yazımı kullanabiliriz. Örneğin:
import os
ls_stdin, ls_stdout, ls_stderr = os.popen3("/bin/ls")
...

5.3  lambda Formları

lambda formları özellikle Lisp kültüründen olanların oldukça yakından tanıdığı bir fonksiyon biçimidir. lambda formları basit fonksiyonlar olarak tanımlanabilir. Özellikle kodun içinde ufak tefek ve o anki duruma özgü işlemler yapmak için lambda formları kullanılabilir. Örneğin bir lambda tanımını kodun içerisinde koşula bağlı bir şekilde yaparak duruma göre değişen bir fonksiyon elde etmek mümkündür. Bir lambda formu şu şekilde tanımlanır:
lambda : 

Dinamik olarak tanımlanan lambda formlarını liste yorumlama özellikleriyle birleştirerek kodu sadeleştirmek mümkündür.

5.4  map(), filter(), reduce() ve enumerate()

map() ve filter() fonksiyonları temelde liste yorumları ile aynı işi yapmaya yararlar. map() fonksiyonu bir fonksiyon ve bir liste olmak üzere iki parametre alır ve sözkonusu fonksiyonu listenin her elemanı üzerinde teker teker çalıştırarak sonucu döndürür. filter() fonksiyonu ise verdiğimiz fonksiyonu ikinci parametresi olan liste üzerinde uygulayarak doğruluk değeri testi yapar ve doğru değeri döndüren elemanlardan oluşan bir listeyi sonuç olarak döndürür. Bu iki fonksiyonu map(, filter(, liste)) şeklinde kullanarak liste yorumlama işlemini taklit etmek mümkündür. Fakat liste yorumları kodu daha okunabilir kıldığından Python'un liste yorumlarını desteklemeyen 2.0'dan önceki sürümleri ile uyumluluğun hedeflendiği durumlar haricinde pek kullanılmazlar.
reduce() fonksiyonu ise diğerlerine oranla daha ilginç bir fonksiyondur. Bir fonksiyon ve bir liste olmak üzere iki parametre alır. Önce listenin birinci ve ikinci elemanları fonksiyona parametre olarak geçirilir. Bu işlemin sonucu alınarak üçüncü eleman ile, sonra da her işlemin sonucu listenin bir sonraki elemanı ile fonksiyona parametre olarak geçirilir ve son elemandan sonra fonksiyonun döndürdüğü değer reduce() fonksiyonunun sonucu olarak döndürülür. Mecburi olmayan üçüncü bir parametre ise ilk değerdir ve listenin en başına yerleştirilerek ilk eleman ile birlikte işleme girmesi sağlanır. Bu fonksiyon özellikle bir listeden düzenli bir veri yapısı oluşturmak gerektiğinde oldukça kullanışlıdır. Örneğin liste yorumlamaları sırasında sonuç olarak elde ettiğimiz listeyi bir sözlük biçimine çevirmek istersek şöyle bir kod yazmamız yeterli olacaktır:
def sozlugeEkle(sozluk, tup):
"""
Bu fonksiyon parametre olarak aldığı sözlüğe
iki elemanlı tüpteki değerleri anahtar:değer
biçiminde ekler

"""

sozluk[tup[0]] = tup[1]
return sozluk

kare_listesi = [(sayi, sayi**2) for sayi in range(10) if sayi%2]
kare_sozlugu = reduce(sozlugeEkle, kare_listesi, {})
"""
Fonksiyon ilk parametre olarak verilerin ekleneceği
sözlüğü aldığından reduce fonksiyonuna üçüncü parametre
olarak boş bir sözlük geçiriyoruz. Bu sayede fonksiyonumuz
şu şekilde çağırılacaktır:

sozlugeEkle({}, (1,1))
sozlugeEkle({1:1}, (3,9))
...

"""

print kare_sozlugu

enumerate() fonksiyonu ise Python 2.3 ile duyurulmuş, diğerlerine oranla yeni bir fonksiyondur. Bu fonksiyon parametre olarak bir liste alır ve listenin her elemanını numaralandırarak bir enumerate nesnesi döndürür. Bu nesneyi diğer herhangi bir liste gibi döngülerde kullanmak mümkündür. Elde edeceğimiz değer her liste elemanı için (, ) şeklinde bir çifttir. Bu sayede örneğin bir listenin elemanlarını numaralandırarak yazdırmamız gerektiğinde kodumuz oldukça sadeleşmiş olacaktır. enumerate() fonksiyonunun güzelliği şu şekilde daha iyi anlaşılabilir:
liste = ["Sıfır","Bir", "İki", "Üç", "Dört", "Beş", "Altı", "Yedi", "Sekiz", "Dokuz"]
#Eski usül eleman yazdırma

for i in range(len(liste)):
print i, "=", liste[i]

#Enumerate ile yazdırma

for i, eleman in enumerate(liste):
print i, "=", eleman

Sonuçta enumerate() kullanılarak yazılan kodun çok daha anlaşılır olacağı ortadadır.

6  Postludium

Python tabiiki sadece bu kadarcık yazıyla tamamen incelenemez, ancak umarım en azından filin kuyruğunu görmenize yardımcı olabilmişimdir. Python her ne kadar sadelik üzerine kurulmuş bir dil olsa da derinlerine indikçe size Äaa adamlar bunu da düşünmüş" dedirtecek ve kod yazarken biraz daha fazla eğlenmenizi sağlayacak birçok inceliğe sahiptir. Bu incelikleri daha detaylarıyla öğrenmek için kaynakçadaki belgelerden faydalanabilirsiniz. Python dünyasına hoşgeldiniz!

Kaynakça

[]
Python Dökümantasyonu (http://www.python.org/doc/current/
[]
Python Kılavuzu (http://www.geocities.com/dinceraydin/python/tut/tut.html)
[]
Dive Into Python (http://www.diveintopyhton.org)
[]
Python Style Guide (http://www.python.org/doc/essays/styleguide.html)
[]
Python, Mustafa Başer, 2002

Yorum yaz! :: Arkadaşına Gönder!

0 yorum yazılmıştır

Yorum yaz!