Ö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'nde
2 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
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
>>>
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.
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
0 yorum yazılmıştır
Yorum yaz!