phpKF - php Kolay Forum  
Ana Sayfa  |  Yardım  |  Üyeler  |  Giriş  |  Kayıt
 
Moderatör Alımı
Sitemize Moderatör alınacaktır dilediğiniz kategoride moderatör olablirsiniz?
Başvuru İçin Tıklayınız
Forum Ana Sayfası  »  Ödev ve Tezler  »  Elektronik & Bilgisayar
 »  Ağaçlar (trees)

Yeni Başlık  Cevap Yaz
Ağaçlar (trees)           (gösterim sayısı: 62)
Yazan Konu içeriği

boşluk

kızılcık
[isimsiz]

Varsayılan Kullanıcı Resmi

Kayıt Tarihi: 03.11.2010
İleti Sayısı: 9.769
Şehir:
Durum: Forumda Değil

E-Posta Gönder
Özel ileti Gönder


5 kere teşekkür edildi.



Konu Tarihi: 06.11.2010- 22:19


AĞAÇLAR (TREES)

Giriş:

Ağaç veri yapısı, elemanlarının birbirlerine liste veri yapısında olduğu gibi göstergeçler (pointers) aracılığı ile bağlandığı bir veri yapısıdır. Bu veri yapısının listelerden farklılığı, liste veri yapısının aksine bir elemanın birden fazla elemana bağlanmasının mümkün olmasıdır. Bu sayede ağaç veri yapısında yer alan elemanlar arasında hierarşik bir diziliş sağlamak mümkündür. Bir ağaç veri yapısında bir elemanın en fazla kaç elemana bağlanabileceği o ağaç veri yapısının derecesini(order) belirtmektedir. Derecesi iki olan ağaç veri yapısı en basit ağaç türü olarak oluşmakta ve ikili ağaç diye adlandırılmaktadır. Aşağıdaki şekilde elemanları tamsayı olan bir ikili ağaç örneği verilmiştir.


Liste veri yapısında herhangi bir elemandan önce (predessor) veya sonra gelen (successor) sadece bir veya sıfır(liste başı ve sonu için) eleman bulunmaktaydı. Agaç veri yapısında ise her elemanın yine bir veya sıfır önce geleni (predessor) bulunurken, o elemandan sonra gelen eleman sayısı birden fazla (en fazla ağacın derecesi kadar) olabilir. Her ağaçta kendisinden önce hiçbir eleman bulunmayan bir eleman bulunur. Bu eleman yukarıdaki şekilde de görüldüğü gibi en üstte yer alan elemandır ve ağacın kökü (root) olarak adlandırılacaktır. Ayrıca kendisinden sonra hiç eleman bulunmayan elemanlar da ağaçta yer alır ve bu elemanlar da ağacın yaprakları (leaves) olarak adlandırılır. Yukarıdaki örnek ikili ağaçta 5 değerine sahip eleman ağacın kökü ve 3,6 ve 13 değerlerine sahip elemanlar da ağacın yapraklarıdır. Ayrıca ağaç veri yapısında herhangibir elemandan sonra gelen elemanlar, o elemanın çocukları (children) olarak adlandırılırken, yine herhangibir elemandan önce yer alan eleman da, o elemanın velisi (parent) olarak adlandırılmıştır. Ayrıca ağaç veri yapısının oluşması için her elemanın sadece bir tek (kök hariç) velisi olması gerektiğine dikkat ediniz.

Liste veri yapısında olduğu gibi ağaç veri yapısında da elemanlar arasında bir sıralama kullanmak mümkündür. İkili arama ağacı (binary search tree) diye adlandırdığımız ağaç veri yapısında bu sıralama ölçütü her elemanın sol tarafında yer alan çocuğundan büyük olması ve sağ tarafında yer alan çocuğundan küçük olması olarak belirlenmiştir. Bu dersimizde anlatım kolaylığının sağlanabilmesi için sunacağımız program parçaları ve uygulamalarda ikili arama ağacı kullanılacaktır. Ancak bu uygulama ve programlar baska ağaç türleri için de kolaylıkla güncellenebilir. Bu noktadan sonra agaç kavramı da ikili arama ağacı anlamında kullanılacaktır.

Aşağıda ağaç veri yapısının C kodu (tree.c) ile tanımı verilmiştir:

struct Node {

struct Node *leftchild, *rightchild;

int key;

};

struct Tree {

struct Node *root;

};

struct Tree *create_tree(struct Tree *tree);

// Agaç göstergeci için bellekte yer ayırır

struct Node *insert(int, struct Node *root);

//Ağaca yeni bir eleman ekle

struct Node *search(int,struct Node *root);

// Belirtilen tamsayıyı ağaçta bul

struct Node *delete_node(int,struct Node *root);

// Değeri belirtilen elemanı ağaçtan çıkar

Yukarıdaki tanımda da görüldüğü gibi ağaç veri yapısına eleman ekleme ve çıkarma işlemleri insert ve delete işlevleriyle gerçekleştirilmektedir. Search işlevi ise değeri belirtilen bir elemanı ağaç içersinde bularak bu elemanı işaret eden bir göstergeç döndürmektedir.

Yukarıda Tree tanımından önce Node adını verdiğimiz bir başka bir yapı tanımı kullanılmıştır. Bu yapı ağaçta yer alacak elemanların türünü belirlemektedir ve Tree yapısı olarak yarattığımız ağacın elemanları Node yapısında tanımlanan şekilde olacaktır. Bu da ağaç yapısı içindeki kök (root) bölümünün Node yapısına bir göstergeç olarak tanımlanmasıyla elde edilmiştir. Yukarıdaki Node tanımına göre yaratılan ağaç tam sayılardan (integers) oluşacaktır. Sadece bu tanımı değiştirerek farklı yapılarda elemanların yer alabileceği değişik ağaçlar tanımlamak da mümkün olabilir. Node tanımında key değişkeni ile ağaçtaki elemanlarının türü belirtilirken, rightchild ve leftchild değişkenleri ile herhangibir elemanı çocuklarına bağlayan göstergeçler tanımlanmıştır.

Tanımlanan Node yapısı aşağıdaki şekilde de görüldüğü gibi ağaç elemanının saklandığı ve çocuklara bağlantıyı sağlayan göstergeçlerin yer aldığı, üç farklı kısımdan oluşmaktadır.


Aşağıdaki şekilde ise Node tanımıyla elde edilen eleman yapılarının oluşturduğu bir ağaç yer almaktadır.



AĞAÇ İŞLEMLERİNİN GERÇEKLEŞİMİ:

Ağaç veri yapısı üzerindeki işlemlerin ne gibi sonuçlar verdiğini inceledikten sonra şimdi bu işlemlerin gerçekleştirimini daha detaylı inceleyebiliriz.

Bir önceki bölümde verilen tanımdaki işlemler aşağıda gerçekleştirilmiştir:


struct Tree *create_tree(struct Tree *tree)

// Agaç gostergeci için bellekte yer ayırır

{

tree=(struct Tree *)malloc(sizeof(struct Tree));

tree->root=0;

return tree;

}

struct Node *insert(int key,struct Node *root)

// Ağaca yeni bir eleman ekler.

{

struct Node *pt=(struct Node *)malloc(sizeof(struct Node));

pt->key=key;

pt->leftchild=0;

pt->rightchild=0;

if (!root)

root=pt;

else

{

if (key > root->key)

root->rightchild=insert(key,root->rightchild);

else

root->leftchild=insert(key,root->leftchild);

}

return root;

}

struct Node *search(int key,struct Node *root)

// key değişkeninde belirtilen elemanı bulur.

{

if (!root)

return root;

else

{

if (key == root->key)

return root;

else if (key > root->key)

return search(key,root->rightchild);

else

return search(key,root->leftchild);

}

}


struct Node *delete_node(int key,struct Node *root)

// Parametre olarak belirtilen değere sahip elamanı bulup ağaçtan çıkarır.

{

struct Node *marker=root, *parent=0, *child=root, *temp;

//Silinecek elemanı bul

while (marker && marker->key!=key)

{

parent=marker;

if (key < marker->key)

marker= marker->leftchild;

else

marker= marker->rightchild;

}

if (!marker)

printf( "Eleman ağaçta bulunamadı\n");

else

{

if (!parent) //kök silinecek

{

if (!marker->rightchild) //kökün sağ çocuğu yok

root=marker->leftchild;

else if (!marker->leftchild) //kökün sol çocuğu yok

root=marker->rightchild;

else { //kökün iki çocuğu da var

for (temp=marker,child=marker->leftchild;

child-> rightchild;

temp=child, child=child->rightchild);

if (child!=marker->leftchild)

{

temp->leftchild=child->leftchild;

child->leftchild=root->leftchild;

}

child->rightchild=root->rightchild;

root=child;

}

}

else if (!marker->rightchild)

//silinecek elemanın sag çocuğu yok

{

if (parent->leftchild==marker)

parent->leftchild=marker->leftchild;

else

parent->rightchild=marker->leftchild;

}

else if (!marker->leftchild)

//silinecek elemanın sol çocuğu yok

{

if (parent->leftchild==marker)

parent->leftchild=marker->rightchild;

else

parent->rightchild=marker->rightchild;

}

else //Silinecek elemanın iki çocuğu da var.

{

for (temp=marker,child=marker->leftchild;

child->rightchild;

temp=child, child=child->rightchild);

if (child!=marker->leftchild)

{

temp->rightchild=child->leftchild;

child->leftchild=marker->leftchild;

}

child->rightchild=marker->rightchild;

if (parent->leftchild==marker)

parent->leftchild=child;

else

parent->rightchild=child;

}

free(marker);

}

return root;

}

Yukarıda tanımlanan işlemlerde Insert ve Search işlevleri özyinemeli olarak tanımlanmışlardır. Eleman ekleme (insert) işlevinde eğer ağaç boş ise yeni bir eleman yaratılmış ve kök (root) göstergeci bu yeni elamanı gösterir hale getirilmiştir. Eğer ağaçta bazı elemanlar var ise bu durumda özyinemeli çağrılarla yeni elemanın ağacın uygun yerine yerleştirilmesi sağlanmıştır. Bu işlev sonuçta ağacın yeni halini gösteren kök degişkenine dönmektedir. Benzer bir yaklaşımla arama (search) işlevinde ise aranan eleman ağaçta bulunmakta ve o elemanı işaret eden göstergeç belirlenmektedir. Eğer aranan eleman ağaçta yok ise göstergecin sıfır olarak döndürüleceğine dikkat ediniz.

Yukarıda tanımlanan işlevlerden eleman silme işlevi (delete) en karmaşık işlev olarak karşımıza çıkmaktadır. Bunun nedeni, işlevin herhangibir eleman silindiğinde ağacın yine ikili tarama ağacı özelliklerini korumasını sağlamasıdır. İkili tarama ağacının korunması için bu işlevde elemanın silinmesinin yanısıra, ağaç üzerinde bazı düzenlemeler de gerçekleştirilmiştir.

Aslında bu işlevi, silinecek elemanın ağacın hangi bölümünde olabileceği olasılıklarına göre değişik alt parçalardan oluşmuş olarak düşünebiliriz. Her alt parçacık oluşan durumda gereken düzenlemeyi yapmak üzere tanımlanmıştır. Şimdi bu işlevi bu alt parçalara göre adım adım inceleyebiliriz.

i) İşlevin başında yer alan while döngüsü silinecek elemanın ağaç üzerindeki yerini tespit etmektedir. Eğer eleman bulunamaz ise marker göstergeci sıfır değerini almakta ve ekrana elemanın bulunamadığına dair bir mesaj gönderilmektedir.

İİ) Elemanın bulunduğu durumda çeşitli olasılıklar tek tek incelenmektedir. İlk olasılık olarak silinecek elemanın kök elemanı olması ele alınmıştır. Bu durum kökün sağ veya sol çocuğunun bulunmaması veya iki çocuğunun da bulunması olarak üç alt durumda incelenmiştir. Kökün sadece bir çocuğu olması durumunda bu çocuk yeni kök haline getirilmektedir. Kökün iki çocuğu olduğu durumda yapılması gereken düzenleme biraz daha karmaşıktır. Kök silineceği için kökün yerine ondan bir önceki veya bir sonraki eleman yerleştirilmelidir. Bu kökün sol tarafında yer alan alt ağacın en sağındaki eleman olabileceği gibi, sağ tarafında yer alan alt ağacın en solunda yer alan eleman da olabilir. Tanımlanan işlevde sol alt ağaç kullanılmıştır. Aşağıdaki şekilde örnek bir ağaç üzerinde kök silindiğinde yapılacak düzenleme ve elde edilen yeni ağaç gösterilmiştir.


•Bu bölümde göstergeçler üzerinde yapılan değişiklikler yukarıdaki şekilde gösterilen düzenlemenin gerçekleştirilmesi için yapılmaktadır. Ağacın yeni şeklinin oluşturulurken elemanların kopyalanmayıp sadece göstergeçlerinin değiştirildiğine dikkat ediniz.

iii) Silme işlevinde ikinci büyük alt parça silinecek eleman kökten farklı bir eleman olduğunda karşımıza çıkmaktadır. Burada yine üç alt bölümde silinecek elemanın sağ veya sol çocuklarının bulunmaması veya iki çocuğunun da bulunması durumları ele alınmıştır. Çocuklardan birisi bulunmadığında yine kökün silinmesi durumunda olduğu gibi, silinecek eleman, velisinin sağinda veya solunda olduğu gözetilerek aradan çıkarılmaktadır. Silinecek elemanın iki çocuğunun bulunduğu durumda ise yine aşağıdaki şekilde gösterildiği gibi bu elemanın sol alt ağacının en sağında bulunan eleman silinecek elemanın yerine kaydırılmaktadır.


Şimdi, tanımlanan ağaç veri yapısına çeşitli elemanlar ekleyen ve çıkaran örneğe aşağıdaki bağlantıdan erişebilirsiniz.


AĞAÇ UYGULAMALARI

İkili arama ağacında saklanan verileri, kullanılan erişim sırasına göre üç değişik şekilde taramak mümkündür. Bu tarama şekilleri sıralı (inorder), sıra önceli (preorder) ve sıra sonralı (postorder) olarak adlandırılmaktadırlar.

i) Sıra önceli(preorder) taramada her elemana o elemanın sol ve sağ alt ağaçlarındaki tüm elemanlardan önce erişilmektedir.

ii) Sıralı(inorder) taramada her elemana , o elemanın sol alt ağacındaki elemanlardan sonra, fakat sağ alt ağacındaki tüm elemanlardan önce ulaşılmaktadır.

iii) Sıra sonralı(postorder) taramada her elemena, o elemanın sol ve sağ alt ağaçlarındaki tüm elemanlardan sonra erişilmektedir.

Aşağıdaki şekilde bir ikili ağaç, ve bu ağacın elemanlarının bu üç değişik tarama yöntemiyle erişilme sıraları verilmiştir.

Bu tarama yöntemlerinin C işlevleri biçiminde gerçekleştirimi aşağıda verilmiştir.


void inordertraversal(struct Node *root)

{

if (root)

{


inordertraversal(root->leftchild);

printf("%d ",root->key);

inordertraversal(root->rightchild);

}

}

void preordertraversal(struct Node *root)

{

if (root)

{

printf("%d ",root->key);

preordertraversal(root->leftchild);

preordertraversal(root->rightchild);

}

}


void postordertraversal(struct Node *root)

{

if (root)

{

postordertraversal(root->leftchild);

postordertraversal(root->rightchild);

printf("%d ",root->key);

}

}
























LİSTELER (LISTS)

Giriş:

Liste, bu veri yapısında yer alan elemanların sıralı bir biçimde saklandığı ve erişilebildiği bir veri yapısıdır. Bu veri yapısındaki elemanları düz bir çizgi üzerinde birbirine bağlanarak sıralanmış olarak düşünebiliriz.

Aşağıda bu veri yapısının C kodu (list.c)ile tanımı verilmiştir:


struct Item {

struct Item *next;

int val;

};


struct List {

struct Item *list;

};


// Boş liste yaratır

struct List *create_list(struct List *pl);

//Listenin başına bir tamsayı ekle

void insert_elm(struct List *pl,int);

// Listenin sonuna bir tamsayı ekle

void append_elm(struct List *pl,int);

// Belirtilen tamsayıyı listeden çıkar

void remove_elm(struct List *pl,int);

// Listedeki eleman sayısını bul

int length(struct List *pl);

// Listedeki elemanları ekrana yaz

void display(struct List *pl);

// Listenin sonunda yer alan elamanın göstergecini bul

struct Item *atEnd(struct List *pl);


Yukarıdaki tanımlamada da görüldüğü gibi liste veri yapısının sonuna yada başına eleman ekleme işlemleri append ve insert işlemleriyle gerçekleştirilmektedir. Remove işlemi ise verilen bir elemanı (listenin herhangibir yerinde olabilir) listeden çıkarmaktadır. Liste veri yapısında elemanlar arasındaki sıralama sadece elemanların listedeki pozisyonlarına dayalı olacaktır.

Yukarıda list yapısının (structure) tanımından önce Item adını verdiğimiz bir başka bir yapı tanımı kullanılmıştır. Bu yapı listede yer alacak elemanları belirlemektedir ve list adı ile yarattığımız listeler aslında Item lardan oluşmaktadır. Yukarıdaki Item tanımına göre yaratılan liste yapısında tam sayılar (integers) eleman olarak yer alacaklardır. Sadece bu yapının tanımını değiştirerek farklı tür ve yapılarda elemanların yer alabileceği değişik listeler tanımlamak da mümkün olabilir. Bu tanımlamada val değişkeni ile listenin elemanlarının türü belirtilirken, next değişkeni ile herhangibir elemanı bir sonraki elemana bağlayacak göstergeç tanımlanmıştır. Liste tanımındaki insert, append gibi fonksiyonlarla bu değeri değiştirmek ve böylece yeni elemanı listede başka elemanlara bağlamak mümkün olmaktadır. Tanımlanan item yapısı aşağıdaki şekilde de görüldüğü gibi liste elemanının saklandığı ve bir sonraki elemana bağlantıyı sağlayan göstergeçin yer aldığı, iki farkli kısımdan oluşmaktadır.


Aşağıdaki şekilde ise Item tanımıyla elde edilen eleman yapılarının oluşturduğu bir liste yer almaktadır.

Tanımlanan liste veri yapısına çeşitli elemanlar ekleyen ve çıkaran örneğe aşağıdaki bağlantıdan erişebilirsiniz.



LİSTE İŞLEMLERİNİN GERÇEKLEŞİMİ

Liste üzerindeki işlemlerin ne gibi sonuçlar verdiğini inceledikten sonra şimdi bu işlemlerin gerçekleştirimini daha detaylı inceleyebiliriz.

Bir önceki bölümde verilen sınıf tanımındaki işlemler aşağıda tanımlanmıştır:


struct List *create_list(struct List *pl)

// Boş liste yaratır

{

pl=(struct List *)malloc(sizeof(struct List));

pl->list=0;

return pl;

}

void insert_elm(struct List *pl,int val)

// listenin başına yeni bir eleman ekler.

{

struct Item *pt=(struct Item *)malloc(sizeof(struct Item));

pt->val=val;

pt->next = pl->list;

pl->list = pt;

}


struct Item *atEnd(struct List *pl)

// listenin son elemanını bulup onu gösteren göstergeçi döner.

{

struct Item *curr;

if (pl->list == 0)

return 0; // liste boş.

curr = pl->list;

while (curr->next)

curr = curr->next;

return curr;

}

void append_elm(struct List *pl,int val)

// listenin sonuna yeni bir eleman ekler.

{

struct Item *pt=(struct Item *)malloc(sizeof(struct Item));

pt->val=val;

pt->next=0;

if (pl->list==0)

pl->list = pt;

else

(atEnd(pl))->next = pt;

}

void remove_elm(struct List *pl,int val)

// Parametre olarak belirtilen değere sahip elamanı bulup listeden çıkarır.

{

struct Item *prv, *pt = pl->list;

// listenin başındaki eleman için.

if ( (pt) && (pt->val==val) )

{

pl->list= pt->next;

free(pt);

}


// listenin ortasında yer alan elemanlar için.

else if (pt)

{

for ( prv=pt, pt= pt->next;

((pt) && (pt->val != val));

prv=prv->next, pt=pt->next);

if (pt->val==val)

{

prv->next=pt->next;

free(pt);

}

}

}

int length(struct List *pl)

{

struct Item *tmp=pl->list;

int i=0;

while (tmp)

{

i++;

tmp=tmp->next;

}

return i;

}

void display(struct List *pl)

{

struct Item *tmp=pl->list;

while (tmp)

{

printf("%d ", tmp->val) ;

tmp=tmp->next;

}

}

Yukarıda tanımlanan işlemlerde insert ve append listenin başına ve sonuna eleman ekleme işlemlerini gerçekleştirmektedir. Append fonsiyonunda listenin son elemanının bulunması için endList fonksiyonu kullanılmıştır. Remove fonksiyonunda ise ilk if ifadesinde eğer listenin ilk elemanı val parametresinde belirtilen değere sahip ise, bu eleman listeden çıkarılmakta, ikinci if ifadesinde yer alan döngüde ise eğer listenin ortasında uygun bir eleman varsa, bu eleman listeden çıkarılmaktadır. Listenin başında yer alan bir elemanın silinmesi için list göstergecinin bir sonraki elemanı gösterir hale getirilmesi ve bu elemanın silinmesi yeterliyken, listenin ortasındaki bir elemanın silinmesi için aşağıdaki şekilde de gösterildiği gibi, ek bir işlem olarak silinecek elemandan bir önceki elemanın next göstergeci, silinecek elemandan bir sonraki elemanı gösteren bir hale getirilmektedir. Bu farklı iki durumdan dolayı, remove fonksiyonu iki ayri bölümden oluşmaktadır. Yine bu veri yapısı için de bir create fonksiyonu tanımlanmış ve bu fonksiyon aracılığı ile bellekten gerekli yer alınmıştır. Ayrıca liste veri yapısı ilk tanımlandığında herhangibir elemana sahip olmadığı için list göstergeci bu yaratma fonksiyonunda sıfıra eşitlenmiştir. Bu işlem yapılmaz ise göstergecin bellekte rastgele bir adresi göstereceğine ve bunun da hatalara yol açabileceğine dikkat ediniz.


Ayrica listenin uzunluğunu bulan ve listenin elemanlarını gösteren fonksiyonlar, length ve display yukarıda tanımlanmıştır.


































VERİ YAPILARI

Liste veri tipinin birkaç metodu daha var. İşte liste nesnelerinin bütün metodları:

append(x)

Listenin sonuna bir eleman ekler; a[len(a):] = [x] ifadesine denktir. .

extend(L)

Listeyi verilen listedeki tüm elemanarı ekleyerek genişletir; a[ len(a):] = L ifadesine denktir. .

insert(i, x)

Verilen konuma bir eleman sokar. İlk argüman elemanın yerleştirileceği indistir. a.insert(0, x) ifadesi x'i listenin başına sokar, ve a.insert(len(a), x) ifadesi a.append(x) ifadesine denktir.

remove(x)

Liste içinde değeri x olan ilk elemanı listeden siler. Böyle bir öğe yok ise bu hatadır.

pop()

Verilen konumdaki elemanı listeden siler ve bunu geri döndürür. Eğer bir indis belirtilmediyse, a.pop() listedeki son elemanı siler ve geri döndürür.

index(x)

Değeri x olan elemanın indisini geri döndürür. Böyle bir eleman yok ise bu hatadır.

count(x)

x'in listede kaç adet bulunduğunu bulur ve bu değeri geri döndürür.

sort()

Listenin elemanlarını sıralar - yerinde.

reverse()

Listenin sırasını tersine çevirir - yerinde.


Liste metodlarının çoğunu kullanan bir örnek:

>>> a = [66.6, 333, 333, 1, 1234.5]

>>> print a.count(333), a.count(66.6), a.count('x')

2 1 0

>>> a.insert(2, -1)

>>> a.append(333)

>>> a

[66.6, 333, -1, 333, 1, 1234.5, 333]

>>> a.index(333)

1

>>> a.remove(333)

>>> a

[66.6, -1, 333, 1, 1234.5, 333]

>>> a.reverse()

>>> a

[333, 1234.5, 1, 333, -1, 66.6]

>>> a.sort()

>>> a

[-1, 1, 66.6, 333, 333, 1234.5]


LİSTELERİN YIĞIN OLARAK KULLANILMASI

Liste metodları listelerin kolayca yığın olarak kullanılmasını sağlarlar. Yığına son giren eleman ilk çıkar. Yığının üzerine eleman eklemek için append() ve en üstteki elemanı almak için indis belirtmeden pop() kullanılır. Örnek:

>>> yigin = [3, 4, 5]

>>> yigin.append(6)

>>> yigin.append(7)

>>> yigin

[3, 4, 5, 6, 7]

>>> yigin.pop()

7

>>> yigin

[3, 4, 5, 6]

>>> yigin.pop()

6

>>> yigin.pop()

5

>>> yigin

[3, 4]


LİSTELERİN KUYRUK OLARAK KULLANILMASI

Listeleri kuyruk olarak da kullanmak mümkün. Bir kuyrukta ilk eklenen eleman ilk alınan elemandır (ilk giren ilk çıkar). Kuyruğun sonuna bir eleman eklemek için append() kullanılır. Sıranın başından bir eleman almak için ise 0 indisi ile pop() kullanılır. Örnek:

>>> kuyruk = ["Ali", "Veli", "Deli yazmış


>>> kuyruk.append("Küpeli") # Küpeli kuyrukta

>>> kuyruk.append("Aylin") # Aylin kuyrukta

>>> kuyruk.pop(0)

'Ali'

>>> kuyruk.pop(0)

'Veli'

>>> kuyruk

['Deli', 'Küpeli', 'Aylin']

FONKSİYONEL PROGRAMLAMA ARAÇLARI

Listelerle kullanıldığında çok faydalı olan yerşeik fonksiyonlar vardır: filter(), map(), ve reduce().

"filter(fonksiyon, sıra)" sıra içerisinden fonksiyon(eleman) ın doğru sonuç verdiği elemanların bulunduğu (mümkünse aynı türden) bir sıra geri döndürür. Örneğin, bazı asal sayıları hesaplamak için şöyle yapılabilir:

>>> def f(x): return x % 2 != 0 and x % 3 != 0

...

>>> filter(f, range(2, 25))

[5, 7, 11, 13, 17, 19, 23]

"map(fonksiyon, sıra)" sıranın her elemanı için fonksiyon(sıra) çağırır ve geri döndürülen değerlerin oluşturduğu listeyi geri döndürür. Örneğin bazı sayıların küplerini hesaplamak için şu yol izlenebilir:

>>> def cube(x): return x*x*x

...

>>> map(cube, range(1, 11))

[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

map(fonksiyon, sıra)] ifadesinde birden fazla sıra da kullanılabilir; ancak bu durumda fonksiyon sıra sayısı kadar argümana sahip olmalıdır. fonksiyon her sıranın uygun elemanını bir argüman olarak alır; ancak sıralardan biri kısa ise eksik elemanlar için fonksiyona None argümanı geçirilir. Eğer fonksiyon adı için de None kullanılırsa argümanlarını geri döndüren bir fonksiyon etkisi yaratılır.

Bu iki özel durumu birleştirerek "map(None, list1, list2)" ifadesi ile bir çift diziyi çiftlerden oluşan bir diziye çevirebiliriz. Örnek:

>>> sira = range(8)

>>> def kare(x): return x*x

...

>>> map(None, sira, map(kare, sira))

[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]

"reduce(fonksiyon, sıra)" ifadesi tek bir değer geri döndürür. Bu değer şöyle elde edilir: iki argümanlı fonksiyona sıranin ilk iki elemanı argüman olarak verilir, sonra da elde edilen sonuç ile sıranin sonraki elemanı argüman olarak verilir,daha sonra yine elde edilen sonuç ile bir sonraki eleman fonksiyona verilir ve bu işlem bütün elemanlar için tekrarlanır. Örneğin 1'den 10'a kadar olan böyle toplanabilir:

>>> def topla(x,y): return x+y

...

>>> reduce(topla, range(1, 11))

55

Sırada sadece bir eleman var ise bunun değeri geri döndürülür; sıra boş ise bir istisna oluşur (exception).

Başlangıç değerini bildirmek için üçüncü bir argüman kullanılabilir. Bu durumda fonksiyona ilk olarak başlangıç değeri ve sıranın ilk elemanına uygulanır ve diğer elemanlar ile devam eder. Örnek:

>>> def sonuc(sira):

... def topla(x,y): return x+y

... return reduce(topla, sira, 0)

...

>>> sonuc(range(1, 11))

55

>>> sonuc([])

0

LİSTE ÜRETEÇLERİ

Liste üreteçleri map(), filter() ve/veya lambda fonksiyonlarını kullanmadan liste yaratmanın kısa bir yoludur. Bu yolla yaratılan liste tanımı genellikle daha kolay anlaşılır olur. Bir liste üreteci bir ifade ve bir for döngüsü ile bunları izleyen sıfır ya da daha fazla for veya if ifadelerinden oluşur. Sonuç kendisini izleyen for ve if bağlamında değerlendirilen ifadeden oluşan bir listedir. Eğer ifade bir demete (değişmez liste [tuple]) dönüşecekse parantez içinde yazılmalıdır.

>>> freshfruit = [' banana', ' loganberry ', 'passion fruit ']

>>> [weapon.strip() for weapon in freshfruit] # elemanları saran

boşlukların atıldığı yeni bir liste

['banana', 'loganberry', 'passion fruit']

>>> vec = [2, 4, 6]

>>> [3*x for x in vec]

[6, 12, 18]

>>> [3*x for x in vec if x > 3]

[12, 18]

>>> [3*x for x in vec if x < 2]

[]

>>> [{x: x**2} for x in vec] # sözlüklerden oluşan bir liste

[{2: 4}, {4: 16}, {6: 36}]

>>> [[x,x**2] for x in vec]

[[2, 4], [4, 16], [6, 36]]

>>> [x, x**2 for x in vec] # hata - demet için parantez gerekir

File "", line 1

[x, x**2 for x in vec]

SyntaxError: invalid syntax

>>> [(x, x**2) for x in vec]

[(2, 4), (4, 16), (6, 36)]

>>> vec1 = [2, 4, 6]

>>> vec2 = [4, 3, -9]

>>> [x*y for x in vec1 for y in vec2]

[8, 6, -18, 16, 12, -36, 24, 18, -54]

>>> [x+y for x in vec1 for y in vec2]

[6, 5, -7, 8, 7, -5, 10, 9, -3]


del DEYİMİ

del deyimi ile bir listeden indisi verilen bir eleman silinebilir. Bu deyim ile bir listeden dilimler de silinebilir (bunu daha önce dilimlere boş bir liste atayarak yapmıştık). Örnek:

>>> a

[-1, 1, 66.6, 333, 333, 1234.5]

>>> del a[0]

>>> a

[1, 66.6, 333, 333, 1234.5]

>>> del a[2:4]

>>> a

[1, 66.6, 1234.5]

del değişkeni tamamen silmek için de kullanılabilir:

>>> del a

Bu aşamadan sonra a ismine değinmek hatadır (aynı isme başka bir değer atanana kadar). Daha sonra del için başka kullanım alanları da göreceğiz.

DEMETLER VE SIRALAR

Listelerin ve karakter dizilerinin indisleme ve dilimleme gibi pek çok ortak özellikleri olduğunu gördük. Bunlar sıra şeklindeki iki veri tipidirler. Python gelişmekte olan bir dil; diğer sıra şeklindeki veri tipleri de Python'a eklenebilir. demet de başka bir sıra şekilli standart veri tipidir .

Bir demet virgül ile ayrılmış birkaç değerden oluşur.

>>> t = 12345, 54321, 'merhaba!'

>>> t[0]

12345

>>> t

(12345, 54321, 'merhaba!')

>>> # demetler iç içe kullanılabilirler :

... u = t, (1, 2, 3, 4, 5)

>>> u

((12345, 54321, 'merhaba!'), (1, 2, 3, 4, 5))

Gördüğünüz gibi çıktıda demetler daima parantez içinde görünürler; ki iç içe geçmiş demetler belli olsun. Demetler parantezli veya parantezsiz olarak yazılabilirler; ancak parantezler genelikle gereklidirler (özellikle de demet daha büyük bir ifadenin içinde geçiyorsa).

Demetlerin pekçok kullanım alanı var: (x,y) koordinat çifti, veri tabanındaki işçi kayıtları vb. gibi. Demetler de karakter dizileri gibi değerleri değiştirilemez veri tipleridir; bunların elemanlarına atama yapılamaz (fakat dilimleme ve birleştirme aracılığı ile bu etki sağlanabilir). Ayrıca değiştirilebilen elemanlardan oluşan demetler oluşturmak da mümkündür (örnek: listelerden oluşan bir demet).

Sıfır veya bir elemanlı demetlerin oluşturulması ile ilgili özel bir problem var: bunların ifade edilmesini sağlayan sözdizim biraz acayip. Boş demetler bir çift boş parantez ile ifade edilir. Tek elemanı olan bir demet için ise elemandan sonra bir virgül kullanılır (tek bir değeri parantez içine almak yeterli değildir). Çirkin ama etkili. Örnek: >>> bos = ()

>>> tekOge = 'merhaba', # >> len(bos)

0

>>> len(tekOge)

1

>>> tekOge

('merhaba',)

t = 12345, 54321, 'merhaba!' ifadesi demetleme (tuple packing) işlemine bir örnektir: 12345, 54321 ve 'merhaba!' değerleri bir demet içinde toplanmışlardır. Bu işlemin tersi de mümkün:

>>> x, y, z = t

Doğal olarak, buna demet açma(sequence unpacking) deniyor . Demet açma sol taraftaki değişken sayısının sıra içindeki öğe sayısına eşit olmasını gerektirir. Çoklu değer atama işleminin aslında demetleme ve demet açmanın bir bileşimi olduğuna dikkat edin. Burada küçük bir asimetri var: birden fazla değeri demetleme her zaman bir demet oluşturur ve demet açma herhangi bir sıra için yapılabilir. Örnek:

>>> paket = 'xyz' # bir karakter dizisi

>>> a,b,c = paket

>>> a

'x'

>>> b

'y'

>>> c

'z'

SÖZLÜKLER

Python'da bulunan bir diğer faydalı veri tipi de sözlüktür. Sözlükler diğer programlama dillerinde ``çağrışımlı bellek'' ( associative memory) veya ``çağrışımlı dizi'' (associative array) olarak bilinirler. Sayılarla indislenen sıralardan farklı olarak, sözlükler anahtarlar (key) ile indislenirler. Anahtar değiştirilemeyen tipdeki herhangi bir veri tipinde olabilir. Sayılar ve karakter dizileri her zaman anahtar olabilirler. Demetler de sayılar, karakter dizileri veya demetler içerdikleri sürece anahtar olabilirler. Bir demet doğrudan ya da dolaylı olarak değiştirilebilir bir nesne içeriyorsa anahtar olarak kullanılamaz. Listeler anahtar olamazlar, çünkü append() ile extend() metodları, dilimleme ve indise değer atama ile değiştirilebilirler.

Bir sözlük anahtar : değer çiftlerinden oluşur. Bir anahtar sözlükte sadece bir defa bulunabilir. Bir çift çengelli parantez boş bir sözlük yaratır : {}. Çengelli parantezlerin içine virgülle ayrılmış anahtar : değer çiftleri koymak anahtar ve değer çiftlerine ilk değerlerini verir. Çıktıya da sözlükler aynı şekilde yazılırlar.

Sözlüklerle ilgili ana işlemler bir değerin bir anahtar ile saklanması ve anahtar verildiğinde değerin bulunmasıdır. del kullanarak bir anahtar : değer çiftini silmek mümkündür. Zaten mevcut olan bir anahtar kullanarak bir değer eklerseniz bu anahtarla bağlantılı eski değer unutulur. Mevcut olmayan bir anahtar ile değer istemek hatalıdır.

Sözlük nesnesinin keys() metodu listedeki bütün anahtarların listesini rasgele sıralı olarak geri döndürür (sıralamak isterseniz listenin sort() metodundan faydalanabilirsiniz) . Bir anahtarın sözlükte olup olmadığını görmek için sözlüğün has_key() metodu kullanılır.

İşte sözlük kullanan küçük bir örnek:

>>> tel = {'jack': 4098, 'sape': 4139}

>>> tel['guido'] = 4127

>>> tel

{'sape': 4139, 'guido': 4127, 'jack': 4098}

>>> tel['jack']

4098

>>> del tel['sape']

>>> tel['irv'] = 4127

>>> tel

{'guido': 4127, 'irv': 4127, 'jack': 4098}

>>> tel.keys()

['guido', 'irv', 'jack']

>>> tel.has_key('guido')

1

KOŞULLAR ÜZERİNE DAHA FAZLA BİLGİ

while ve if deyimlerinde kıyaslama dışında da operatörler kullanılabilir.

in ve not in kıyaslama operatörleri bir değerin bir sıra içinde olup olmadığını sınarlar. is ve is not operatörleri iki nesnenin tamamen aynı nesne olup olmadıklarını sınarlar (bu sadece liste gibi değiştirilebilir nesnelerde önemlidir). Bütün kıyaslama operatörleri aynı önceliğe sahiptirler ve bu sayısal operatörlerinkinden düşüktür.

Kıyaslamalar zincirlenebilir: a < b == c gibi.

Kıyaslamalar mantıksal operatörler and ve or ile birleştirilebilirler, ve kıyaslamanın sonucu (ya da herhangi bir mantıksal ifade) not ile değillenebilirler. Bunların hepsi de kıyaslama operatörlerinden düşük önceliğe sahiptirler ve aralarında en yüksek öncelikli olan notve en düşük öncelikli olan or operatörüdür. Örneğin A and not B or C ifadesi (A and (not B)) or C ifadesine eştir. İstenen bileşimi elde etmek için parantezler kullanılabilir.

and ve or mantıksal operatörlerine kısa devre operatör de denir. Bunların argümanları soldan sağa değerlendirilir ve sonuç belli olur olmaz değerlendirme işlemi kesilir. Örneğin A ve C doğru, fakat B yanlış olsun. A and B and C ifadesinde C ifadesi değerlendirilmez (çünkü C nin değeri sonucu değiştirmez). Genel olarak bir kısa devre operatörü Bool değil de genel bir değer gibi kullanıldığında en son değerlendirilen argümanın değeri geri döndürülür.

Bir kıyaslamanın ya da mantıksal ifadenin sonucunu bir değişkene atamak mümkündür:

>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'

>>> non_null = string1 or string2 or string3

>>> non_null

'Trondheim'

C dilinin tersine, Python'da ifadelerin içinde atama olamayacağına dikkat edin. C programcıları bundan şikayetçi olabilirler; ancak bu C programlarında sık karşılaşılan bazı hataları engellemektedir (== yerine = yazmak gibi).

SIRALARIN VE DİĞER VERİ TİPLERİNİN KIYASLANMASI

Sıra nesneleri yine sıra şeklindeki diğer nesnelerle kıyaslanabilirler. Önce ilk iki eleman kıyaslanır. Bunlar farklı ise sonuç belli olmuştur; eşit olmaları halinde sonraki iki eleman kıyaslanır ve sıralardan biri tükenene kadar bu işlem tekrarlanır. Eğer kıyaslanan iki öğe de sıra ise bunlar da kendi aralarında kıyaslanırlar. İki sıranın bütün öğeleri aynı bulunursa bu sıralar eşit kabul edilir. Eğer bir sıra diğerinin başından bir kısmı ile aynı ise kısa olan sıra küçük kabul edilir. Karakterlerin kıyaslanmasında ASCII karakter sırası kullanılır. Aynı türden sıraların kıyaslanmasına bazı örnekler :

(1, 2, 3) < (1, 2, 4)

[1, 2, 3] < [1, 2, 4]

'ABC' < 'C' < 'Pascal' < 'Python'

(1, 2, 3, 4) < (1, 2, 4)

(1, 2) < (1, 2, -1)

(1, 2, 3) == (1.0, 2.0, 3.0)

(1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)

Farklı türden nesnelerin kıyaslanmasının yasal olduğuna dikkat edin. Türler alfabetik sırayla dizilmiştir (ingilizce isimlerine göre). Yani: liste < karakter dizisi < demet (list < string < tuple).

MODÜLLER

Python yorumlayıcısını kapatıp tekrar açarsanız yaptığınız tanımlar ( fonksiyonlar ve değişkenler) kaybolur. Uzunca bir program yazmak isterseniz bunun için programınızı bir metin editörü ile hazırlayıp yarattığınız dosyayı yorumlayıcı girişi olarak kullanırsanız daha iyi olur. Bu işleme betik (script) yazmak denir. Programınız uzadıkça bunu daha kolay idare etmek için birkaç dosyaya bölmek isteyebilirsiniz. Yazdığınız bir fonksiyonu tanımını kopyalamaya ihtiyaç duymaksızın birkaç programda kullanmayı da isteyebilirsiniz.

Bu iş için Python'da modül denen dosyalar var. Bunlara yazılan tanımlar diğer modüllere ya da etkileşimli kipteki yorumlayıcıya import deyimi ile yüklenebilirler.

Modüller .py uzantılı metin dosyalarıdır ve içlerinde Python deyimleri ve tanımları bulur. Bir modül içerisinde __name__ global değişkeninin değeri (bir karakter dizisi) o modülün adını verir. Örneğin, favori metin editörünüz ile fibo.py adlı bir dosya yaratıp Python yorumlayıcısının bulabileceği bir dizine kaydedin. Dosyanın içeriği de şu olsun:

# Fibonacci sayıları modülü

def fib(n): # n e kadar Fibonacci serisini yazdır

a, b = 0, 1

while b < n:

print b,

a, b = b, a+b

def fib2(n): # n e kadar Fibonacci serisi geri döndürür

sonuc = []

a, b = 0, 1

while b < n:

sonuc.append(b)

a, b = b, a+b

return sonuc


Yorumlayıcıyı açıp bu modülü şu komut ile yükleyin:

>>> import fibo

Bu fibo içindeki fonksiyon tanımlarını yürürlükte olan simge tablosuna eklemez; sadece modül adı fibo tabloya eklenir. Fonksiyonlara modül adı kullanarak erişilebilir:

>>> fibo.fib(1000)

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

>>> fibo.fib2(100)

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

>>> fibo.__name__

'fibo'

Bir fonksiyonu sık sık kullanmak isterseniz bunu yerel bir isme atayabilirsiniz:

>>> fib = fibo.fib

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

MODÜLLER ÜZERİNE DAHA FAZLA BİLGİ

Fonksiyon tanımlarının yanısıra modül içinde çalıştırılabilir ifadeler de olabilir. Bu ifadeler modülün ilk kullanıma hazırlanması için kullanılabilirler ve sadece modülün ilk yüklenişinde çalışırlar.6.1

Her modülün o modül içindeki bütün fonksiyonlar tarafından global simge tablosu olarak kullanılan kendi simge tablosu vardır. Bu özellik sayesinde modülü yazan kişi rahatlıkla modül içnde global değişkenler kullanabilir. Modülü kullanan diğer kişilerin global değişkenleri ile isim çakışması olmaz. Modul içindeki global değişkenlere de modulAdi.degiskenAdi şeklinde ulaşmak ve istenirse bunları değiştirmek mümkündür.

Modüller diğer modülleri yükleyebilirler. Bütün import ifadelerinin modülün (ya da betiğin) başına konması gelenektendir; ancak şart değildir. Yüklenen modüller kendilerini yükleyen modülün global simge tablosuna ekleniriler.

import deyiminin bir modüldeki isimleri doğrudan yükleyen modülün simge tablosuna ekleyen kullanım şekli var. Örnek:

>>> from fibo import fib, fib2

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

Bu kullanım şekinde yüklemenin yapıldığı modül adı yerel simge tablosuna eklenmez (yani örnekteki codefibo tanımlı değildir).

Bir modülde tanımlanmış bütün isimleri de yüklemek şu şekilde mümkündür:

>>> from fibo import *

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

Bu altçizgi (_) ile başlayanlar dışındaki bütün isimleri yükler.

MODÜL ARAMA YOLU

spam isimli bir modül yüklenmek istendiğinde yorumlayıcı önce çalıştırıldığı dizinde ve sonra PYTHONPATH ortam değişkenince tanımlanan dizinler içinde spam.py isimli bir dosya arar. PYTHONPATH dizin isimlerinden oluşan bir listedir ( PATH gibi). Arana dosya bulunmazsa arama kurluma bağlı başka bir yolda da aranabilir. Unix işletim sisteminde bu .:/usr/local/lib/python dizinidir.

Aslında modüller sys.path değişkeninde bulunan dizin listesinde aranırlar. Bu değişken değerini betiğin çalıştırıldığı dizin, PYTHONPATH ve kuruluma bağlı diğer dizinlerden alır. sys.path değişkeni sayesinde Python programları modül arama yolunu değiştirebilirler.

“DERLENMİŞ” Python DOSYALARI

Derlenmiş Python dosyaları programların çalışmaya başlaması için gereken süreyi kısaltırlar. Örneğin spam.py adlı dosyanın bulunduğu dizinde spam.pyc adlı bir dosya varsa bu module spam modülünün ``bayta derlenmiş'' halidir. spam.py dosyasının son değiştirilme tarihi spam.pyc dosyasının içinde de kayıtlıdır ve bu tarihler aynı değil ise .pyc dosyası dikkate alınmaz.

spam.pyc dosaysının oluşması için bir şey yapmanız gerekmez. spam.py her ne zaman başarılı olarak derlenirse programın derlenmiş hali spam.pyc dosyasına kaydedilir. Bunun yapılamaması bir hata değildir; herhangi bir nedenle .pyc dosyası tam olarak yazılamazsa geçersiz sayılır ve dikkate alınmaz. .pyc dosyalarının içeriği platformdan bağımsızdır. Bu sayede bir Python modülü dizini farklı mimarideki makineler tarafından paylaşılabilir.

Uzmanlar için birkaç ip ucu:

•Python yorumlayıcısı -O parametresi ile çalıştırıldığında eniyileştirilmiş (optimized) kod üretilir ve .pyo uzantılı dosyalarda saklanır. Eniyileştircinin (optimizer) şu anda pek bir yararı olmuyor; sadece assert deyimler ile SET_LINENO komutlarını siliyor. -O parametresi kullanıldığında tüm baytkodu eniyileştirilir, .pyc dosyaları göz ardı edilir ve .py dosyaları eniyileştirilmiş baytkoduna derlenir.

•Yorumlayıcıya iki tane -O parametresi (-OO) vermek baytkodu derleyicisinin bazı ender durumlarda doğru çalışmayan programlara neden olan eniyilştirmeler yapmasına neden olur. Şu anda sadece __doc__ karaktr dizileri silinerek daha küçük .pyo dosyaları üretilmektedir. Bazı programların çalışması bunların varlığına bağımlı olabileceğinden bu parametreyi kullanırken dikkatli olun.

•Bir program .pyc ya da .pyo dosyasından okunduğunda .py dosyasından okunan halinden daha hızlı çalışmaz; sadece yüklenme süresi kısalır.

•Bir betik komut satırından ismi verilerek çalıştırıldığında bunun baytkodu asla bir .pyc ya da .pyo dosyasına yazılmaz. Bu yüzden betiğin başlama süresini kısaltmak için bunun bir kısmı bir modüle aktarılarak ve bu modülü yükleyen küçük bir başlatıcı betik kullanılarak kısaltılabilir. Komut satırından bir .pyc ya da .pyo dosyası da ismi verilerek doğrudan çalıştırılabilir.

•spam.py dosyası olmadan da spam.pyc (ya da -O kullanıldığında spam.pyo) dosyası kullanılabilir. Bunlar bir Python kodu kütüphanesinin tersine mühendisliği zorlaştıran şekilde dağıtılmasında kullanılabilir.

•compileall modülü bir dizindeki bütün dosyalar için spam.pyc (ya da -O kullanıldığında spam.pyo) dosyaları yaratabilir.


STANDART MODÜLLER

Python zengin bir standart modül kütüphanesine sahiptir. Bazı modüller yorumlayıcı ile bütünleşiktir. Bu modüller dilin parçası olmadıkları halde verimlerini artırmak ya da sistem çağrıları gibi şletim sistemine ait özelliklere erişim için yrumlayıcı içine dahil edilmişlerdir. Bunlara iyi bir örnek her Python yorumlayıcısına dahil edilen sys modülüdür. sys.ps1 ve sys.ps2 değişkenleri de birincil ve ikincil komut satırı olarak kullanılan karakter dizilerini belirlerler:

>>> import sys

>>> sys.ps1

'>>> '

>>> sys.ps2

'... '

>>> sys.ps1 = 'C> '

C> print 'Böö !'

Böö !

C>

Bu iki değişken yorumlayıcı sadece etkileşimli kipte iken tanımlıdırlar.

sys.path değişkeni de yorumlayıcının modül arama yolunu belirler. Bu değerini ortam değişkeni PYTHONPATH belirler. PYTHONPATH değişkenine değer atanmadıysa sys.path varsayılan (default) değerini alır. Bunun değeri listelere uygulana işlemler ile değiştirilebilir:

>>> import sys

>>> sys.path.append('/ufs/guido/lib/python')

dir() FONKSİYONU

Yerleşik fonksiyon dir() bir modülün hangi isimleri tanımladığını bulmak içik kullanılır. Bu fonksiyon karakter dizilerinden oluşan bir liste geri döndürür:

>>> import fibo, sys

>>> dir(fibo)

['__name__', 'fib', 'fib2']

>>> dir(sys)

['__name__', 'argv', 'builtin_module_names', 'copyright', 'exit',

'maxint', 'modules', 'path', 'ps1', 'ps2', 'setprofile', 'settrace',

'stderr', 'stdin', 'stdout', 'version']

Argüman kullanmadan çağırılan dir() fonksiyonu o anda tanımlamış olduğunuz isimleri geri döndürür:

>>> a = [1, 2, 3, 4, 5]

>>> import fibo, sys

>>> fib = fibo.fib

>>> dir()

['__name__', 'a', 'fib', 'fibo', 'sys']

Bunun değişken, modül, fonksiyon vs. gibi her tip ismi listelediğine dikkat ediniz.

dir() yerleşik fonksiyon ve değişkenlerin isimlerini listelemez. Bunların bir listesini isterseniz, standart modül __builtin__ içinde bulabilirsiniz:

>>> import __builtin__

>>> dir(__builtin__)

['AccessError', 'AttributeError', 'ConflictError', 'EOFError', '

IOError',

'ImportError', 'IndexError', 'KeyError', 'KeyboardInterrupt',

'MemoryError', 'NameError', 'None', 'OverflowError', 'RuntimeError',

'SyntaxError', 'SystemError', 'SystemExit', 'TypeError', 'ValueError',

'ZeroDivisionError', '__name__', 'abs', 'apply', 'chr', 'cmp', '

coerce',

'compile', 'dir', 'divmod', 'eval', 'execfile', 'filter', 'float',

'getattr', 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'len', '

long',

'map', 'max', 'min', 'oct', 'open', 'ord', 'pow', 'range', '

raw_input',

'reduce', 'reload', 'repr', 'round', 'setattr', 'str', 'type', '

xrange']

PAKETLER

Paketler ``noktalı modül isimleri'' kullanarak Python'un modül isim alanının düzenlenmesinde kullanılırlar. Örneğin modül adı A.B adı "A" olan bir paket içindeki "B" adlı alt modülü gösterir. Nasıl modüller farklı modül yazarlarını birbirilerinin kullandığı global değişkenleri dert etmekten kurtarıyorsa, paketler de NumPy ya da PyOpenGL gibi çok sayıda modül içeren paketlerin biribirilerinin modül isimlerinin çakışması tehlikesinden kurtarır.

Ses dosyaları ve ses verisi üzerinde işlem yapacak bir modül kolleksiyonu (bir ``paket'') geliştirmek istediğinizi düşünelim. Farklı fromatlardaki ses dosyalarını (.wav, .aiff, .au gibi dosya uzantıları olan) biribirine dönüştürmek, seslere efekteler uygulamak veya seslerı filtrelemek için pek çok modüle ihtiyacınız olacak. Paketinizin muhtemel dizin yapısı şöyle olabilir:

Sound/ Paketin en üst seviyesi

__init__.py paketi ilk kullanıma hazırlama

Formats/ Farklı dosya formatları için alt paket

__init__.py

wavread.py

wavwrite.py

aiffread.py

aiffwrite.py

auread.py

auwrite.py

...

Effects/ ses efektlerı alt pakedi

__init__.py

echo.py

surround.py

reverse.py

...

Filters/ filtre alt pakedi

__init__.py

equalizer.py

vocoder.py

karaoke.py

...

__init__.py dosyaları Python'un bu dizinleri paket içeren dizinler olarak algılaması için gereklidirler. Bunlar aynı isimli dizinlerin modül arama yolunda bulunacak diğer geçerli modülleri istem dışı saklamasını engeller. __init__.py boş bir dosya olabileceği gibi paketi ilk çalışmaya hazırlayabilir ya da daha sonra açıklanacak olan __all__ değişkenine değer atıyor olabilir.

Pakedin kullanıcısı paketten dilediği bir modülü yükleyebilir.

import Sound.Effects.echo

Bu Sound.Effects.echo modülünü yükler. Modüle tüm ismi ile atıfta bulunulmalı:

Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4)

Aynı modülü yüklemenin bir diğer yolu:

from Sound.Effects import echo

Bu da echo alt modülünü yükler; ancak bunu paket adı verilmeden erişilebilir kılar ve modül şu şekilde kullanılabilir:

echo.echofilter(input, output, delay=0.7, atten=4)

Bir diğer yol da istene fonksiyon ya da değişkeni doğrudan yüklemektir:

from Sound.Effects.echo import echofilter

Bu da echo modülünü yükler; ancak echofilter() fonksiyonnu doğrudan erişilebilir kılar:

echofilter(input, output, delay=0.7, atten=4)

from paket import isim kullanılırken isim bir alt modül, alt paket ya da paket içinde tanımlı bir fonksıyon, sınıf veya değişken ifade eden herhangi bir isim olabilir. import deyimi önce ismin pakette tanımlı olup olmadığına bakar; tanımlı değil ise bunun bir modül olduğunu varsayar ve bunu yüklemeye teşebbüs eder. Modülü bulamaz ise ImportError istisnası oluşur.

import item.subitem.subsubitem ifadesinde ise son ismin dışındaki isimler paket olmalıdır. Son isim bir modül veya paket olabilir; ancak bir önceki ismin içinde tanımlanan bir fonksiyon ya da değişken olamaz.

BİR PAKETTEN * YÜKLEMEK

Kullanıcı from Sound.Effects import * yazdığında ne olur ? Dosya sistemine ulaşılıp paketin içinde hangi alt paketlerin olduğunun bulunması ve hepsinin yüklenmesi beklenir. Ne yazık ki bu işlem küçük/ büyük harf ayrımının olmadığı Windows ve Mac işetim sistemlerinde pek iyi çalışmaz. Bu işletim sistemlerinde ECHO.PY gibi bir dosyanın echo, Echo veya ECHO isimlerinden hangisi ile yüklenmesi gerektiğini belirlemenin garantili bir yolu yoktur. Örneğin, Windows 95 dosya adlarının ilk harfini daima büyük harf ile gösterir. DOS'un 8+3 harflik dosya adı uzunluğu kısıtlaması da uzun modül isimleri için sorun olmaktadır.

Tek çözüm paket yazarının açık bir paket indeksi hazırlamasıdır. Bir paketin __init__.py dosyası __all__ adlı bir liste tanımlıyorsa bu liste from package import * ifadesi kullanıldığında yüklenecek modül isimlerinin listesi olarak kullanılır. Pedein yeni bir sürümü hazırlandığında bu listenin uygun şekilde güncellenmesi paket yazarının sorumluğundadır. Eğer paketten * yüklemeye ihtiyaç duyulmayacağına karar verilirse bu özellik kullanılmayabilir. Örneğin Sounds/Effects/__init__.py dosyasının içeriği şöyle olabilir:

__all__ = ["echo", "surround", "reverse yazmış


Bu from Sound.Effects import * ifadesinin Sound paketinden isimleri __all__ içinde geçen üç modülün yüklemesini sağlar.

_all__ tanımlanmamış ise from Sound.Effects import * ifadesi Sound.Effects paketindeki bütün alt modülleri yürülükte olan isim alanına yüklemez; sadece Sound.Effects pakedinin ve içindeki isimlerin yüklenmesini sağlar ( muhtemelen __init__.py) dosyasını çalıştırdıktan sonra). Bundan önceki import deyimlerince yüklenen alt paketler de yüklenir. Şu koda bir bakalım:

import Sound.Effects.echo

import Sound.Effects.surround

from Sound.Effects import *

Bu örnekte echo ve surround modülleri from...import ifadesi çalıştırıldığında Sound.Effects paketinde tanımlı oldukları için yürürlükte olan isim alanına yüklenirler. Bu __all__ tanımlı olduğunda da bu çalışır.

Genel olarak bir modül ya da paketten * yüklemek hoş karşılanmaz; çünkü çoğunlukla zor okunan koda neden olur. Bunun etkileşimli kipte kullanılmasının bir sakıncası yoktur. Ayrıca bazı modüller sadece belirli bir kalıba uyan isimleri verecek şekilde tasarlanmışlardır.

from Paket import gerekli_altmodül ifadesini kullanmanın hiç bir kötü tarafı yoktur. Yükleyen modül farklıpaketlerden aynı isimli modüller yüklemeye gereksinim duymadığı sürece tavsiye edilen kullanım şekli de budur.

BİRBİRLERİNİ YÜKLEYEN MODÜLLER

Alt modüller çoğu kez birbirilerine atıfta bulunurlar. Örneğin surround modülü echo modülüne ihtiyaç duyabilir. Aslında bu türden atıflar öyle yaygındır ki import deyimi standart modül arama yoluna bakmadan önce çağırıldığı paketin içinde arama yapar. Bu şekilde surround modülü import echo veya from echo import echofilter ifadeleri ile kolayca echo modülüne kavuşabilir. Yüklenmek istenen modül içinde bulunan pakette (yükleme yağmaya çalışan modülün bulunduğu paket) bulunamaz ise import deyimi aynı isimli üst seviyeli bir modül arar.

Paketler Sound paketindeki gibi alt paketler şeklinde düzenlenmişler ise farklı alt paketler içindeki modüllerin birbirilerine atıfta bulunmasının kısa bir yolu yoktur; paketin tam adı kullanılmalıdır. Örneğin, Sound.Filters.vocoder modülünün echo modülünü kullanması gerekiyor ise from Sound.Effects import echo ifadesi ile buna erişebilir.

GİRİŞ VE ÇIKIŞ

Bir programın çıktısını sunmanın birkaç yolu vardır; veri yazdırılabilir ya da gelecekte kullanılabilecek şekilde bir dosyaya kaydedilebilir. Bu bölümde giriş ve çıkış ile ilgili olanakların bazılarına değineceğiz.

DAHA GÜZEL ÇIKIŞ BİÇİMİ

Buraya kadar değerleri yazdırmanı iki yolunu gördük: deyim ifadeleri ve print deyimi. Üçüncü bir yol da dosya nesnelerinin write() metodudur. Standart çıktı dosyasına sys.stdout şeklinde atıfta bulunulabilir.

Çoğu zaman boşluklar ile biribirinden ayrılmış değerlerden daha iyi biçimlendirilimiş bir çıktıya ihtiyaç duyulur. Çıktınızı biçimlendirmenin iki yolu var. İlki bütün karakter dizisi işlemlerini dilimleme ve birleştirme ile yapıp istediğiniz herhangi bir biçimi elde etmek. string standart modülü karakter dizilerinin istenen sütün genişliğine kadar boşluklar ile doldurulmasını sağlayan ,daha sonra değineceğimiz, bazı faydalı fonksiyonlara sahiptir. İkinci yol ise sol argümanı bir karakter dizisi olan % operatörünü kullanmaktır. % operatörü sol argümanını sağdaki argümanına uygulanacak sprintf() tarzı biçim karakter dizisi olarak yorumlar ve biçimleme işleminden sonra bir karakter dizisi geri döndürür.

Sayısal değerleri karakter dizisine çevirmek için ise değer repr() fonksiyonuna geçirilebilir ya da diğer ters tırnak işareti ( ``) içine alınabilir. İşte birkaç örnek:

>>> x = 10 * 3.25

>>> y = 200 * 200

>>> s = 'The value of x is ' + `x` + ', and y is ' + `y` + '...'

>>> print s

The value of x is 32.5, and y is 40000...

>>> # Ters tırnaklar sayılar dışındaki tipler ile de çalışır:

... p = [x, y]

>>> ps = repr(p)

>>> ps

'[32.5, 40000]'

>>> # Karakter dizisinde ise tırnaklar ve ters bölü işareti eklenir:

... hello = 'hello, world\n'

>>> hellos = `hello`

>>> print hellos

'hello, world\n'

>>> # Ters tırnakların argümanı bir demet de olabilir:

... `x, y, ('spam', 'eggs')`

"(32.5, 40000, ('spam', 'eggs'))"


Sayıların kare ve küplerinden oluşan bir tablo yazdırmanın iki yolu vardır:

>>> import string

>>> for x in range(1, 11):

... print string.rjust(`x`, 2), string.rjust(`x*x`, 3),

... # Üst satırın sonundaki virgüle dikkat edin.

... print string.rjust(`x*x*x`, 4)

...

1 1 1

2 4 8

3 9 27

4 16 64

5 25 125

6 36 216

7 49 343

8 64 512

9 81 729

10 100 1000

>>> for x in range(1,11):

... print '%2d %3d %4d' % (x, x*x, x*x*x)

...

1 1 1

2 4 8

3 9 27

4 16 64

5 25 125

6 36 216

7 49 343

8 64 512

9 81 729

10 100 1000

Sütünların arasındaki bir karakterlik boşluk print tarafından eklenir; argümanların arasına daima bir boşluk karakteri eklenir.

Bu örnek karakter dizilerinin başını boşluklar ile doldurup bunları sağ tarafa dayayan string.rjust() fonksiyonunu kullanmaktadır. Buna benzer string.ljust() ve string.center() fonksiyonları da vardır. Bunlar bir şey yazdırmaz; sadece yeni bir karakter dizisi geri döndürürler. Verilen karakter dizisi uzun ise kırpılmaz ve aynen geri döndrürlür; bu sütünlarınızın bozulmasına sebep olmasına rağmen hatalı bir değer göstermekten iyidir. Büyük bir değeri kırpmayı gerçekten istiyorsanız dilimleme ile bunu yapabilirsiniz ("string.ljust(x, n)[0:n]" gibi).

string.zfill() fonksiyonu ise rakamlar içeren karakter dizilerinin başını sıfırlar ile doldurur. Bu fonksiyon artı ve eksi işaretlerini de dikkate alır:

>>> import string

>>> string.zfill('12', 5)

'00012'

>>> string.zfill('-3.14', 7)

'-003.14'

>>> string.zfill('3.14159265359', 5)

'3.14159265359'


% operatörü şu şekilde kullanılır:

>>> import math

>>> print 'PI sayısının yaklaşık değeri: %5.3f' % math.pi

PI sayısının yaklaşık değeri: 3.142

Karakter dizisinin içinde birden fazla biçim varsa sağ operand olarak bir demet kullanmak gerekir:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}

>>> for name, phone in table.items():

... print '%-10s ==> %10d' % (name, phone)

...

Jack ==> 4098

Dcab ==> 7678

Sjoerd ==> 4127

Çoğu biçim aynı C dilindeki gibi çalışır ve doğru veri tipinin geçirilmesi gerekir; bu yapılamaz ise bir istisna oluşur. %s biçiminin kullanımı daha rahattır; verilen argüman karakter dizisi değilse yerleşik fonksiyon str() ile karakter dizisine dönüştürülür. Genişlik ya da hassasiyeti belirtmek için * ile bir tamsayı argüman kullanılabilir. C dilindeki %n ve %p biçimler ise desteklenmemektedir.

Eğer bölmek istemediğiniz gerçekten uzun bir biçim karakter diziniz varsa biçimlendirmek istediğiniz argümanlara konumu yerine ismiyle atıfta bulunabilmeniz güzel olur. Bu aşağıda gösterildiği gibi %(isim)biçim şeklinde yapılabilir:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}

>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table

Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Bu özellik bütün yerel değişkenlerin bulunduğu bir sözlük geri döndüren yerleşik fonksiyon vars() ile beraber kullanıldığında faydalı olur.

DOSYA OKUMA VE YAZMA

open() fonksiyonu bir dosya nesnesi geri döndürür ve genellikle iki argüman ile kullanılır: "open(dosya_adı, mod)"

>>> f=open('/tmp/workfile', 'w')

>>> print f



İlk argüman dosya adını içeren bir karakter dizisidir. İkincisi ise dosyanın nasıl kullanılacağını belirten karakterlerden oluşur. Erişim modu dosyadan sadece okuma yapılacak ise 'r', sadece yazma için 'w' (anı isimli bir dosya zaten var ise bu silinir) ve dosyanın sonuna eklemeler yapmak için 'a' olur. 'r+' modu dosyayı hem okuma hem de yazma yapmak için açar. mod argümanı seçimliktir; kullanılamaması halinde 'r' olduğu varsayılır.

Windows ve Macintosh üzrinde moda eklenen 'b' harfi dosyayı binary modunda açar; yani 'rb', 'wb', ve 'r+b' gibi modlar da vardır. Windows metin ve binary dosyaları arasında ayrım yapmaktadır; metin dosyalarında okuma veya yazma işlemlerinde satır sonu karakterleri otomatik olarak biraz değişir. Bu görünmez değişiklik ASCII metin dosyaları için iyidir; anacak JPEG resimler veya .EXE dosyalar gibi binary verileri bozar.

DOSYA NESNELERİNİN METODLARI

Bundan sonraki örneklerde f adlı bir dosya nesnesinin önceden yaratılmış olduğunu varsayacağız.

Dosyanın içeriğini okumak için belirli miktarda veriyi okuyup bunu karakter dizisi olarak geri döndüren f.read(boy) metodu kullanılabilir. boy okunacak bayt sayısını belirleyen seçimlik bir argümandır; kullanılmaması halinde dosyanın tamamı okunur. Dosyanın sonuna gelindiğinde f.read() boş bir karakter dizisi ( "") geri döndürür.

>>> f.read()

'Dosyanın tamamı bu satırdan oluşuyor.\n'

>>> f.read()

''

f.readline() dosyadan tek bir satır okur. Satırın sonundaki yeni satır karakteri (\n) korunur; ancak dosya yeni bir satır ile bitmiyor ise son satırda bu karakter silinir. Bu özellik geri döndürülen değerin birden fazla anlama gelmesini engeller; f.readline() boş bir karakter dizisi geri döndürdüğünde dosyanın sonuna ulaşılırken boş bir satır tek bir '\n' karakteri ile ifade edilir.

>>> f.readline()

'Bu dosyanın ilk satırı.\n'

>>> f.readline()

'Dosyanın ikinci satırı\n'

>>> f.readline()

''

f.readlines() dosya içindeki bütün satırların bulunduğu bir liste geri döndürür. Seçimlik parametre boy_ipucu kullanılması durumunda ise dosyadan boy_ipucu kadar ve bundan bir satır tamamlamaya yetecek kadar fazla bayt okunur ve bunlar yine satırlar listesi şeklinde geri döndürülür.

>>> f.readlines()

['Bu dosyanın ilk satırı.\n', 'Dosyanın ikinci satırı\n']

f.write(karakter_dizisi) metodu karakter_dizisi içeriğini dosyaya yazar ve None geri döndürür.

>>> f.write('Bu bir deneme satırıdır.\n')

f.tell() dosya nesnesinin dosya içindeki konumunu belirten bir tamsayı geri döndürür (dosyanın başından bayt cinsinden ölçülür). "f.seek(uzaklık, nereden)" ile de dosyanın içinde istenen konuma gidilebilir. Konum uzaklık ile referans noktası nereden değerlerinin toplanması ile bulunur. nereden 0 olursa dosyanın başını, 1 o andaki konumu, 2 ise dosyanın sonunu belirtir. nereden kullanılmaz ise 0 olduğu varsayılır ve referans noktası olarak dosyanın başı alınır.

>>> f=open('/tmp/workfile', 'r+')

>>> f.write('0123456789abcdef')

>>> f.seek(5) # Dosyadaki 5'inci bayta git

>>> f.read(1)

'5'

>>> f.seek(-3, 2) # Sondan 3'üncü bayta git

>>> f.read(1)

'd'

Dosya ile işiniz bittiğinde metodunu f.close() çağırarak dosyayı kapatabilir ve dosyanın işgal ettiği sistem kaynaklarını serbest bırakabilirsiziz. f.close() çağırıldıktan sonra dosya üzerinde başka işlem yapmaya devam etmek mümkün değildir:

>>> f.close()

>>> f.read()

Traceback (most recent call last):

File "", line 1, in ?

ValueError: I/O operation on closed file

Dosya nesnelerinin isatty() ve truncate() gibi pek sık kullanılmayan başka metodları da vardır.

pickle MODÜLÜ

Karakter dizileri kolayca dosyalara yazılıp dosyalardan okunabilirler. Sayılar biraz zahmetlidir; çünkü read() metodu sadece karakter dizileri geri döndürür ve bunların '123' gibi bir değeri alıp sayısal değeri 123'ü geri döndüren string.atoi () fonksiyonundan geçirilmeleri gerekir. Listeler, sözlükler ve sınıf fertleri (class instances) gibi daha karmaşık veri türlerini dosyalara kaydetmek isterseniz işler oldukça zorlaşır.

Programcıları karmaşık veri türlerini saklamak için kodlamak ve hata ayıklamak ile uğraştırmak yerine Python bu iş için pickle adlı standart modülü sağlar. Bu hayret verici modül neredeyse herhangi bir Python nesnesini (bazı Python kodu biçimlerini bile !) karakter dizisi ile ifade edilebilecek hale getirebilir ve bu halinden geri alabilir. Bu dönüşüm ve geri kazanım işlemleri arasında nesne bir dosyaya kaydedilebilir ya da ağ bağlantısı ile uzaktaki başka bir makineye gönderilebilir.

x gibi bir nesneniz ve yazma işlemi için açılmış f gibi bir dosya nesneniz varsa bu nesneyi dosyaya aktarmanız için tek satırlık kod yeterli olur:

pickle.dump(x, f)

Nesneyi geri almak için ise f okumak için açılmış bir dosya nesnesi olsun:

x = pickle.load(f)

Birden fazla nesnenin dönüştürülmesi gerekiyor ya da dönüştürülmüş olan nesnelerin dosyaya yazılması istenmiyor ise pickle farklı şekilde kullanılır. Bunları pickle modülünün dokümanlarından öğrenmek mümkündür.

pickle modülü saklanabilen ve başka programlar tarafından ya da aynı programın farklı çalışma zamanlarında kullanılabilecek Python nesneleri yapmanın standart yoludur. pickle modülü çok yaygın kullanıldığından Python genişletme modülleri yazan çoğu programcı matrisler gibi yeni veri tiplerinin doğru olarak dönüştürülebilir ve geri alınabilir olmasına özen gösterirler.

HATALAR VE İSTİSNALAR

Şu ana kadar hata mesajlarından pek bahsedilmedi; ancak örnekleri denediyseniz muhtemelen birkaç tane görmüşsünüzdür. Birbirinden ayırt edilebilen en az iki tür hata mevcuttur: sözdizim hataları ve istisnalar.

SÖZDİZİM HATALARI

Sözdizim hataları ayrıştırma (parsing) hataları olarak da bilinirler ve Python öğrenirken en çok bunlar ile karşılaşırsınız:

>>> while 1 print 'Merhaba'

File "", line 1

while 1 print 'Merhaba'

^

SyntaxError: invalid syntax

Ayrıştırıcı (parser) sorun olan satırı basar ve satır içinde hatanın algılandığı ilk noktayı küçük bir `ok' ile gösterir. Hata oktan önce gelen kısımdan kaynaklanmaktadır. Örnekte hata print anahtar kelimesinde fark edilmektedir; çünkü ondan önce bir iki nokta üst üste (":") karakteri eksiktir. Dosya adı ve satır numarası da yazdırılmaktadır ki yorumlayıcı girişinin bir dosyadan gelmesi durumunda hatanın nereden kaynaklandığını bilesiniz.

İSTİSNALAR

Bir deyim ya da ifade sözdizimsel olarak doğru olsa da yürütülmek istendiğinde bir hataya sebep olabilir. İcra sırasında meydana gelen hatalara istisna denir. İstisnaları nasıl ele alabileceğinizi yakında öğreneceksiniz. Çoğu istisnalar programlar tarafından ele alınmaz ve aşağıdakiler gibi hata mesajları ile sonuçlanırlar:

>>> 10 * (1/0)

Traceback (most recent call last):

File "", line 1

ZeroDivisionError: integer division or modulo

>>> 4 + spam*3

Traceback (most recent call last):

File "", line 1

NameError: spam

>>> '2' + 2

Traceback (most recent call last):

File "", line 1

TypeError: illegal argument type for built-in operation

Hata mesajının son satırı sorunun ne olduğunu belirtir. İstisnaların farklı türleri vardır ve istisnanın türü hata mesajının bir bölümü olarak yazdırılır. Örneklerdeki istisna türleri: ZeroDivisionError, NameError ve TypeError. İstisna türü olarak yazdırılan karakter dizisi meydana gelen istisnanın yerleşik (built-in) ismidir. Bu bütün yerleşik istisnalar için geçerlidir; ancak kullanıcı tanımlı istisnalar için böyle olmayabilir. Standart istisna isimleri yerleşik belirteçlerdir ( identifier); ayrılmış anahtar kelimeler değil.

Satırın devamı istisna türüne bağlı detaylardan oluşur ve anlamı istisna türüne bağlıdır.

Hata mesajının baş kısmında istisnanın meydana geldiği yer yığın dükümü şeklinde görülür. Bu genellikle istisnanın gerçekleştiği noktaya gelene kadar işletilen kaynak kodu şeklinde olur; ancak standart girdiden okunan satırlar gösterilmez.

Yerleşik istisnalar ve bunların anlamları için Python ile gelen dokümanlardan yararlanılabilir.

İSTİSNALARIN ELE ALINMASI

Belirli istisnaları ele alan programlar yazmak mümkündür. Aşağıdaki örnek kullanıcıdan geçerli bir tamsayı girilene kadar kullanıcıdan giriş yapması istenir. Control-C tuş kombinasyonu (ya da işletim sisteminin destekldiği başka bir kombinasyon) ile kullanıc programdan çıkabilir. Kullanıcın sebep olduğu bu olay ise KeyboardInterrupt istisnasının oluşmasına neden olur.

>>> while 1:

... try:

... x = int(raw_input("Lütfen bir ra



Yeni Başlık  Cevap Yaz



Forum Ana Sayfası  »  Ödev ve Tezler  »  Elektronik & Bilgisayar
 »  Ağaçlar (trees)

Forum Ana Sayfası


 


Benzer konular
Başlık Yazan Cevap Gösterim Son ileti
Konu Klasör Öldükten Sonra Dirilmek (Ağaçlar) eren79 0 125 29.10.2010- 00:41
Konu Klasör Hiç ağaçlar kendi kendine sandal olabilir mi? murat 0 65 28.10.2010- 20:13

Etiketler   Ağaçlar,   trees


Forum Yazılımı:   php Kolay Forum (phpKF)  ©  2007 - 2010   phpKF Ekibi

Duyurucu

 RSS Beslemesini Görmek için Tıklayın   RSS Beslemesini Google Sayfama Ekle   RSS Beslemesini Yahoo Sayfama Ekle