5. Veri Yapıları

Bu bölümde öğrendiğiniz bazı şeyler daha ayrıntılı açıklanmakta ve bazı yeni konulara da değinilmektedir.

5.1. Listeler Üzerine Daha Fazla Bilgi

Liste veri türünün birkaç yöntemi daha var. İşte liste nesnelerinin bütün yöntemleri:

list.append(x)

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

list.extend(L)

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

list.insert(i, x)

Belirtilen konuma bir eleman yerleştirir. İlk bağımsız değişken elemanın yerleştirileceği indistir. a.insert(0, x) ifadesi x'i listenin başına yerleştirir, ve a.insert(len(a), x) ifadesi a.append(x) ifadesine denktir.

list.remove(x)

Liste içinde değeri x olan ilk elemanı listeden siler. Böyle bir öğe yok ise ValueError istisnası oluşur.

list.pop([i])

Belirtilen konumdaki elemanı listeden siler ve bunu geri döndürür. Eğer bir indis belirtilmezse, a.pop() listedeki son elemanı siler ve döndürür. (i etrafındaki köşeli ayraçlar bu bağımsız değişkenin seçimlik olduğunu belirtir. Bu yazım biçimini Python belgelerinde sıkça görebilirsiniz.)

list.clear()

Listenin tüm elemanlarını siler. del a[:] işlemine denktir.

list.index(x[, ilk[, son]])

Değeri x olan ilk elemanın indisini döndürür. Böyle bir öğe yok ise ValueError istisnası oluşur.

İsteğe bağlı bağımsız değişkenler ilk ve son, dilim gösterimindeki gibi yorumlanır ve aramayı belirli bir aralıkla sınırlamak için kullanılır. Döndürülen indis, ilk'e göre değil listenin başlangıcına göre hesaplanır.

list.count(x)

x'in listedeki miktarını bulur ve bu değeri geri döndürür.

list.sort(*[, key=None, reverse=False])

Listeyi kendi içinde sıralar. İsteğe bağlı bağımsız değişkenler anahtar kelime olarak belirtilebilir ve sıralamayı özelleştirmek için kullabılabilir.

key ile yinelemedeki her öğeden bir karşılaştırma anahtarı çıkarmak için kullanılan tek bağımsız değişkenli bir işlev belirtilir (örneğin, key=str.lower). None öntanımlıdır (öğeler doğrudan karşılaştırılır).

reverse mantıksal bir değerdir. True belirtilirse liste elemanları tersine sıralanır.

list.reverse()

Listenin sırasını kendi içinde tersine çevirir.

list.copy()

Listenin sığ bir kopyasını döndürür. a[:] ifadesine denktir.

Liste yöntemlerinin çoğunu kullanan bir örnek:

>>> meyveler = ['portakal', 'elma', 'armut', 'muz', 'kivi', 'elma', 'muz']
>>> meyveler.count('elma')
2
>>> meyveler.count('mandalina')
0
>>> meyveler.index('muz')
3
>>> meyveler.index('muz', 4)  # 4. konumdan sonraki muzun konumunu bul
6
>>> meyveler.reverse()
>>> meyveler
['muz', 'elma', 'kivi', 'muz', 'armut', 'elma', 'portakal']
>>> meyveler.append('üzüm')
>>> meyveler
['muz', 'elma', 'kivi', 'muz', 'armut', 'elma', 'portakal', 'üzüm']
>>> meyveler.sort()
>>> meyveler
['armut', 'elma', 'elma', 'kivi', 'muz', 'muz', 'portakal', 'üzüm']
>>> meyveler.pop()
'üzüm'

5.1.1. Listelerin Yığın Olarak Kullanılması

Liste yöntemleri listelerin kolayca yığın olarak kullanılmasını sağlar. 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]

5.1.2. Listelerin Kuyruk Olarak Kullanılması

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"]
>>> 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']

5.1.3. İşlevsel Yazılım Geliştirme Araçları

Listelerle kullanıldığında çok faydalı olan yerleşik işlevler vardır: filter(), map(), ve reduce().

filter(işlev, sıra) sıra içerisinden işlev(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(işlev, sıra) sıranın her elemanı için işlev(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(işlev, sıra) ifadesinde birden fazla sıra da kullanılabilir; ancak bu durumda işlev sıra sayısı kadar bağımsız değişkene sahip olmalıdır. işlev her sıranın uygun elemanını bir bağımsız değişken olarak alır; ancak sıralardan biri kısa ise eksik elemanlar için işleve None bağımsız değişkeni aktarılır. Eğer işlev adı için de None kullanılırsa bağımsız değişkenlerini döndüren bir işlev 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(işlev, sıra) ifadesi tek bir değer geri döndürür. Bu değer şöyle elde edilir: iki bağımsız değişkenli işleve sıranın ilk iki elemanı bağımsız değişken olarak verilir, sonra da elde edilen sonuç ile sıranın sonraki elemanı bağımsız değişken olarak verilir, daha sonra yine elde edilen sonuç ile bir sonraki eleman işleve verilir ve bu işlem bütün elemanlar için tekrarlanır. Örneğin 1'den 10'a kadar olanlar 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 bağımsız değişken kullanılabilir. Bu durumda işleve 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

5.1.4. Liste Üreteçleri

Liste üreteçleri map(), filter() ve/veya lambda işlevlerini 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 = ['  muz', '  loganberry ', 'passion fruit  ']
>>> [weapon.strip() for weapon in freshfruit] # elemanları saran
boşlukların atıldığı yeni bir liste
['muz', '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 "<stdin>", line 1, in ?
    [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]
>>> [vec1[i]*vec2[i] for i in range(len(vec1))]
[8, 12, -54]

Liste üreteçlerinin for döngülerine benzer davranması için, döngü değişkenine yapılan atamalar üreteç dışında da görünürler:

>>> x = 100                     # bu değişecek
>>> [x**3 for x in range(5)]
[0, 1, 8, 27, 64]
>>> x
4                               # range(5) için son değer
>>

5.2. del Deyimi

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 deyimi tamamen silmek için de kullanılabilir:

>>> del a

Bu aşamadan sonra a ismine başvuru bir 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.

5.3. Demetler (tuples)

Listelerin ve dizgelerin indisleme ve dilimleme gibi pek çok ortak özellikleri olduğunu grdük. Bunlar sıra şeklindeki iki veri türüdür. Python gelişmekte olan bir dil; diğer sıra şeklindeki veri türleri de Python'a eklenebilir. Demet de başka bir sıra şekilli standart veri türüdür.

Bir demet virgül ile ayrılmış bir kaç 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 dizgeler gibi değerleri değiştirilemez veri türleridir; 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', # <--satır sonundaki virgüle dikkat
>>> 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 dizge
>>> a,b,c = paket
>>> a
'x'
>>> b
'y'
>>> c
'z'

5.4. Sözlükler (Çağrışımlı Listeler)

Python'da bulunan bir diğer faydalı veri türü de sözlüktür. Sözlükler diğer yazılımlama dillerinde ``çağrışımlı bellek'' (associative memory) veya ``çağrışımlı dizi'' (associative array) olarak bilinir. Sayılarla indislenen sıralardan farklı olarak, sözlükler anahtarlar (key) ile indislenir. Anahtar değiştirilemeyen türdeki herhangi bir veri türünde olabilir. Sayılar ve dizgeler her zaman anahtar olabilir. Demetler de sayılar, dizgeler veya demetler içerdikleri sürece anahtar olabilir. 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() yöntemleri, dilimleme ve indise değer atama ile değiştirilebilir.

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ır.

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() yöntemi listedeki bütün anahtarların listesini rasgele sıralı olarak geri döndürür (sıralamak isterseniz listenin sort() yönteminden faydalanabilirsiniz). Bir anahtarın sözlükte olup olmadığını görmek için sözlüğün has_key() yöntemi 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

dict() işlevi anahtar-değer çiftlerinden oluşan demetlerden sözlükler üretir. Çiftlerin bir kalıba uyduğu durumlarda, liste üreteçleri ile anahtar-değer çiftleri kısaca ifade edilebilir.

>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>>> dict([(x, x**2) for x in vec])     # liste üreteci kullanarak
{2: 4, 4: 16, 6: 36}

5.5. Döngü Teknikleri

Sözlükler üzerinde döngüler kurarken o anki değer items() yöntemi ile aynı anda elde edilebilir.

>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print k, v
...
gallahad the pure
robin the brave

Bir sıra üzerinde dönerken konum indisi ve ona karşılık gelen değer de enumerate() işlevini kullanarak aynı anda elde edilebilir.

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print i, v
...
0 tic
1 tac
2 toe

Aynı anda iki sıra üzerinde ilerlemek için ise zip() işlevi ile bunlar çiftler haline getirilebilir.

>>> sorular = ['adın', 'görevin', 'favori rengin']
>>> cevaplar = ['Adnan', 'Uyumak', 'Mavi']
>>> for s, c in zip(sorular, cevaplar):
...     print 'Senin %s ne? %s.' % (s, c)
...
Senin adın ne? Adnan.
Senin görevin ne? Uyumak.
Senin favori rengin ne? Mavi.

5.6. Koşullu İfadeler Üzerine Daha Fazla Bilgi

while ve if deyimlerinde kıyaslama dışında da işleçler kullanılabilir.

in ve not kıyaslama işleçleri bir değerin bir sıra içinde olup olmadığını sınar.

is ve is not işleçleri 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 işleçleri aynı önceliğe sahiptirler ve bu sayısal işleçlerinkinden düşüktür.

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

Kıyaslamalar mantıksal işleçler and ve or ile birleştirilebilirler ve kıyaslamanın sonucu (ya da herhangi bir mantıksal ifade) not ile değillenebilir. Bunların hepsi de kıyaslama işleçlerinden düşük önceliğe sahiptirler ve aralarında en yüksek öncelikli olan not ve en düşük öncelikli olan or işleçidir. Ö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 işleçlerine kısa devre işleç de denir. Bunların bağımsız değişkenleri 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 işleçi Bool değil de genel bir değer gibi kullanıldığında en son değerlendirilen bağımsız değişkenin 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 yazılımcıları bundan şikayetçi olabilirler; ancak bu C yazılımlarında sık karşılaşılan bazı hataları engellemektedir (== yerine = yazmak gibi).

5.7. Listeler, Dizgeler ve Demetler Arasında Kıyaslama

Sıra nesneleri yine sıra şeklindeki diğer nesnelerle kıyaslanabilir. Ö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ır. İ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 < dizge < demet (list < string < tuple).[69]



[69] Değişik türlerin kıyaslanmasına ilişkin kurallara güvenilmemeli; gelecek Python sürümlerinde bu kurallar değişebilir!