AST415 Astronomide Sayısal Çözümleme - I

Ders - 03 Döngü Yapıları, Listeler, Demet Nesneleri

Doç. Dr. Özgür Baştürk
Ankara Üniversitesi, Astronomi ve Uzay Bilimleri Bölümü
obasturk at ankara.edu.tr
http://ozgur.astrotux.org

Neden Döngülere İhtiyaç Duyarız?

Aşağıdaki şekilde bir liste halinde verilmiş bir grup sıcaklığı santigrad dereceden ($^{\circ}$C), fahrenheit dereceye ($^{\circ}$F) dönüştürmek istiyor olalım.

-20.0 -4.0
-15.0 5.0
-10.0 14.0
-5.0 23.0
+0.0 32.0
+5.0 41.0
10.0 50.0
15.0 59.0
20.0 77.0
30.0 86.0
35.0 95.0
40.0 104.0

Bu problemin basit bir çözümüne aşağıdaki kod satırlarıyla ulaşabiliriz.

In [1]:
C = -20; F = 9.0/5*C + 32; print(C, F)
C = -15; F = 9.0/5*C + 32; print(C, F)
C = -10; F = 9.0/5*C + 32; print(C, F)
C = -5; F = 9.0/5*C + 32; print(C, F)
C = 0; F = 9.0/5*C + 32; print(C, F)
C = 5; F = 9.0/5*C + 32; print(C, F)
C = 10; F = 9.0/5*C + 32; print(C, F)
C = 15; F = 9.0/5*C + 32; print(C, F)
C = 20; F = 9.0/5*C + 32; print(C, F)
C = 25; F = 9.0/5*C + 32; print(C, F)
C = 30; F = 9.0/5*C + 32; print(C, F)
C = 35; F = 9.0/5*C + 32; print(C, F)
C = 40; F = 9.0/5*C + 32; print(C, F)
-20 -4.0
-15 5.0
-10 14.0
-5 23.0
0 32.0
5 41.0
10 50.0
15 59.0
20 68.0
25 77.0
30 86.0
35 95.0
40 104.0

Bu çözümün birkaç önemli problemi var.

  1. Çıktısının formatı çok çirkin! Ancak bu C ve F'yi doğrudan ekrana yazdırmak yerine daha önce öğrendiğimiz formatlama seçeneklerini kullanarak aşılabilir.

  2. Asıl önemlisi, aynı ifadeyi defalarca yazıyor olmamız! Elimizin altında bir bilgisayar olduğuna göre bunu daha kolay yapabilmeliyiz. Tüm bilgisayar programlama dillerinde olduğu gibi Python'da da bunun çözümü döngü yapıları kullanmaktır. Python'da iki çeşit döngü yapısı bulunmaktadır: $while$ döngüleri ve $for$ döngüleri

Başa Dön

While Döngüleri

$while$ döngüsü verilen bir şart sağlanana kadar döngü yapısı içerisinde yer alan ifadeleri tekrar tekrar çalıştırır.

Örnek: Amacımız verilen liste dahilinde C = -5 $^{\circ}$C'den başlayıp, C ≤ 40 $^{\circ}$C olduğu sürece 5 $^{\circ}$C'lik artışlarla sıcaklık değerini arttırıp, karşılık geldiği ($^{\circ}$F dereceyi hesaplamak ve her ikisini ekrana yazdırmak!

Algoritma:
C = -20
          C ≤ 40 OLDUĞU SÜRECE aşağıdaki adımları TEKRARLA!:
                    F = (9 / 5.) * C + 32
                    C ve F'yi ekrana yazdır
                    C'yi 5 arttır

Başa Dön

Blok Kullanımı

Döngü içerisinde çalışması istenen tüm ifadeler içeri doğru aynı miktarda bloklanmalıdır. Bunun miktarı bir zorunluluk olmamakla birlikte, önerilen bir standart \"<TAB>" ya da 4 boşluk kullanmaktır.

Aşağıdaki kod segmentini; kağıt kalem kullanarak, her bir değişkenin her çalışma anındaki değerini yazıp, ekrana yazılacakları tahmin etmek suretiyle elinizle (ing. trace) çalıştrınız. Daha sonra aşağıdaki kodu çalıştırıp, aradaki (varsa) farkların nedenlerini anlamaya çalışmalısınız (Elle çalıştırmak → “trace” etmek). Elle çalıştırmak, programcılık öğrenirken ve kodunuzdaki olası hataları bulmaya çalışırken çok faydalı bir egzersizdir.

In [2]:
print("------------------") # tablo basligi
C = -20 # C icin baslangic degeri
dC = 5 # dongu icinde C'nin arttirilacagi deger
while C <= 40: # dongunun calismasi icin kosul
    # while dongusu icindeki kod blogu
    F = (9.0/5)*C + 32 # Dongudeki ilk ifade
    print(C, F) # Dongudeki ikinci ifade
    C = C + dC # Dongudeki ucuncu ifade
    # while dongusunden cikis
# while disindaki kod blogu
print ("------------------") # Dongu sonrasi tablo sonu
print("C'nin dongu disindaki degeri: ", C)
------------------
-20 -4.0
-15 5.0
-10 14.0
-5 23.0
0 32.0
5 41.0
10 50.0
15 59.0
20 68.0
25 77.0
30 86.0
35 95.0
40 104.0
------------------
C'nin dongu disindaki degeri:  45

İşlemlerin Kısa Gösterimi

Bir değişken ismi, türüne göre (int, float, str gibi) yaratılan bir nesne (object)'ye verilen bir isimdir. Değişkene yeni bir değer atadığınız vakit, yeni bir nesne yaratılır ve değişken ismi artık bu yeni nesnenin ismi olur. Bu nedenle matematiksel olarak yanlış gibi görünen aşağıdaki ifade bilgisayar bilimlerinde doğru bir atama ifadesidir.

$$C = C + dC$$

Bu ifadeyle C değişkenin atıfta bulunduğu tamsayı ($int$) nesnesinin değeri dC tamsayı ($int$) nesnesinin değeri kadar arttırılmakta, bu iki nesnenin ikisi birden tamsayı ($int$) nesnesi olduğu için yeni yaratılan nesne de tamsayı nesnesi olup, değeri de onların toplamı olmaktadır. C'nin daha önce atıfta bulunduğu nesne ise yok edimiş, C yeni yaratılan tamsayı nesnesinin ismi olmuştur. Bu ifade kısaca aşağıdaki şekilde de yazılabilir.

$$C += dC$$

Bu kısa gösterim diğer işlemler için de aynen kullanılabilir.

$C$     $-=$     $dC$
$C$     $*=$     $dC$
$C$     $/=$     $dC$

Boolean İfadeler

Karşılaştırma ve Mantıksal Operatörler

Boolean İfadeler: Sonucu DOĞRU ($TRUE$) ya da YANLIŞ ($FALSE$) olan ifadelerdir.

Örnek 1:
$C == 40$ # C “eşittir” 40
$C != 40$ # C “eşit değildir” 40
$C >= 40$ # C 40'tan “büyük ya da ona eşittir”
$C <= 40$ # C 40'tan “küçük ya da ona eşittir”
$C > 40$ # C 40'tan “büyüktür”
$C < 40$ # C 40'tan “küçüktür”

Bu karşılaştırma operatörlerini yanı sıra mantıksal operatörler ($not$, $and$, $or$, $xor$) de Boolean ifadelerde kullanılıır.

In [3]:
x = 0; y = 1.2
print(x >= 0 and y < 1)
print(x >= 0 or y < 1)
print(x > 0 or y > 1)
print(x > 0 or not y > 1)
print(-1 < x <= 0) # -1 < x and x <= 0
print(not (x > 0 or y > 0))
False
True
True
False
True
False

Herhangi bir programlama dilinde iki reel sayının eşitliğinin karşılaştırılması şartına dayanan döngüler yazmak iyi bir fikir değildir. İki reel sayıyı karşılaştırmanın neden iyi bir fikir olmadığını aşağıdaki örnekle anlamaya çalışalım.

In [4]:
%%capture
#Asagidaki kodu calistirmak istediginizde yukaridaki satiri siliniz
epsilon = 1.0
while 1.0 != 1.0 + epsilon:
    print("...................", epsilon)
    epsilon /= 2.0
print("epsilon'un son degeri: ", epsilon)

Şimdi bu kodun ne yaptığını anlamaya çalışalım. 1 değerinden başlatılan $epsilon$ bir $while$ döngüsü dahilinde sürekli 2'ye bölünerek küçültülüyor. Makinenizin izin verdiği en küçük değere ("makine epsilonu") kadar küçültüldüğünde $epsilon$ 0'a çok yakın olduğundan 0 olarak değerlendiriliyor ve $1.0 != 1.0 + epsilon$ koşulu artık sağlanmıyor (yani 1 = 1 + 0) ve döngü tamamlanıyor. Son olarak da epsilon'un en son değeri (0 kabul edilen) ekrana yazdırılıyor. Herhangi iki reel sayıyı $while$ döngüsünün şartını "eşit değil" (!=) üzerine değil de "eşit" (==) üzerine kurarak çalıştırırsanız programınızı sonsuz döngüye sokabilirsiniz. Şimdi bu probleme bir başka örnek verelim:

In [5]:
a = 1/947.0*947
b = 1
if a != b: # Henuz if ogrenmediniz!
    print("Yanlis sonuc!")
Yanlis sonuc!

Bir önceki derste gördüğünüz bazı sayıların ikilik sistemde tam gösterilememesi problemi burada karşımıza tekrar çıkmaktadır. 1/947.0 işleminin sonucu ikilik sayı sisteminde tam gösterilemediği için en yakın ikilik sayıya yuvarlanmakta, bu sayı 947 ile çarpılınca 1'den (çok az miktar olmakla birlikte makine epsilonundan büyük) daha büyük bir sayı çıkmaktadır. Henüz Python'da şartlı yapıları ($if$ ile başlayan blok) öğrenmemiş olsanız da ilgili kod bloğunun ne yaptığını tahmin edebilirsiniz: Bu sayıyı 1'le karşılaştırıyor ve 1'den farklı olduğu sürece ekrana "Yanlis sonuc!" ifadesini yazdırıyor. Eğer bu blok bir $while$ bloğu olsaydı ($if$ yerinde $while$ yazıyor olsaydı), bu blok "sonsuz kez" çalışacaktı.

Bu iki örnekten çıkarılması gereken ders iki reel sayıyı $a == b$ ya da $a != b$ şeklinde karşılaştırmanın beklenmedik sonuçlara yol açabileceğidir. Bunun yerine yeterince küçük bir tolerans değeri tanımlayıp karşılaştırmayı bu tolerans değeri dahilinde yapmak iyi bir yöntemdir.

In [6]:
a = 1/947.0*947
b = 1
tolerans = 1e-15 # kucuk bir tolerans degeri
# a ile b arasindaki fark tolerans degerinden kucuk ise 
# bu iki deger birbirine esit kabul edilsin...
if abs(a - b) < tolerans: # 
    print("Dogru sonuc!")
Dogru sonuc!

Listeler

Python'a özel, elemanları rastgele seçilmiş nesne türleri olabilen, bir nesnedir. Listenin herhangi eleman(lar)ı indeksleme yoluyla çağrılır. Listenin bir bölümünü alma işlemine dilimleme (ing. slicing) denir.

In [7]:
C = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
print(C[1]) # Listenin ikinci (1 numarali indeks) elemani
print(C[0]) # Listenin birinci (0 numarali indeks) elemani
print(C[-1]) # Listenin sonuncu (-1 numarali indeks) elemani
print(C[0:2]) # Listenin 1. elemanindan 3. elemanina (3. eleman haric) kadarki bolumu
print(C[1:2]) # Bir dilim oldugu icin tek bir elemani olan (listenin 2. elemani olan bir liste
print(C[-1:-3])
print(C[-1:-3:-1]) # Yukaridaki ornekte [40:35] sonucuna ulasmak istiyorsaniz dogru yolu budur
print(C[-2:])
print(C[-3:-1]) # Listenin sondan 3. elemanindan son elemanina (son eleman haric) kadarki bolumu
print(C[:]) # Listenin tamami
print(C[:4]) # Listenin basindan (0) 5. elemanina (4) kadar (5. eleman haric) kadarki bolumu
print(C[6:]) # Listenin yedinci (6) elemanindan son elemani dahil sonuna kadarki bolumu
print(C[:-3]) # Listenin basindan sondan 3. elemanina (sondan 3. eleman haric) kadarki bolumu
print(C[0:10:2]) # Listenin basindan 11. elemanina (11 haric) 2ser adimla giderek dilimle
print(C[::3]) # Listenin sonuna kadar 3er 3er giderek dilimle
print(C[::-2]) # Listenin basindan sonuna ters yonde (yani sonundan basina) 2ser adimla dilimle
-15
-20
40
[-20, -15]
[-15]
[]
[40, 35]
[35, 40]
[30, 35]
[-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
[-20, -15, -10, -5]
[10, 15, 20, 25, 30, 35, 40]
[-20, -15, -10, -5, 0, 5, 10, 15, 20, 25]
[-20, -10, 0, 10, 20]
[-20, -5, 10, 25, 40]
[40, 30, 20, 10, 0, -10, -20]

Listeler Üzerinde İşlemler

Herhangi bir listeye yeni bir eleman eklemek ($append$), çıkarmak ($delete$ ve $remove$), istediğniz yere eleman yerleştirmek ($insert$), herhangi bir elemanın indeksini bulmak ($index$) gibi işlemleri yapabilmek için verilen fonksiyonları liste.fonksiyon_adi(arguman) şeklindeki yazımla gerçekleştirebilirsiniz. Bu şekilde kullanılan fonksiyonlara $metot$ (ing. method, attribute) adı verilir. Aşağıda verilen metotlar liste nesnesinin metotlarıdır.

In [8]:
C = [-10, -5, 0, 5, 10, 15, 20, 25, 30]
C.append(35) # Listenin sonuna 35 sayisini ekler!
print(C)
C.insert(0,-15) # O. indekse (en basa) -15 sayisini yerlestirir!
print(C)
C.remove(10) # C listesinden 10 sayisini cikarir!
print(C)
del C[-2] # C listesinin sondan ikinci elemanini siler!
print(C)
print(len(C)) # Listenin eleman sayisini verir
print(C.index(5)) # 5 sayisinin indeksini verir
[-10, -5, 0, 5, 10, 15, 20, 25, 30, 35]
[-15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35]
[-15, -10, -5, 0, 5, 15, 20, 25, 30, 35]
[-15, -10, -5, 0, 5, 15, 20, 25, 35]
9
4

İki listeyi ucuca eklemek için toplama işlemi kullanılır. Dikkat: Toplama işlemi verilen iki listenin elemanlarını birbiri ile toplamaz, bu listeleri ucuca ekler!

In [9]:
C = [-10, -5, 0, 5, 10, 15, 20, 25, 30]
print("Eklemeden once: ",C)
C = C + [40, 45]
print("Ekledikten sonra: ",C)
Eklemeden once:  [-10, -5, 0, 5, 10, 15, 20, 25, 30]
Ekledikten sonra:  [-10, -5, 0, 5, 10, 15, 20, 25, 30, 40, 45]

Liste elemanlarına karşılık gelen yeni değişkenler yaratmak için kompakt bir yazım kuralı (syntax) da bulunmaktadır.

In [10]:
birliste = ["Adana", "kebap", 1] # istahinizi actiysam ozur diliyorum
il, yemek, plaka = birliste
print("{:d} - {:s}'da {:s} yenir.".format(plaka, il, yemek))
1 - Adana'da kebap yenir.

Bir listenin kopyasını oluşturmak için atama operatörü farklı bir şekilde kullanılır.

In [11]:
a = [1,2,3,4]
b = a # a listesine bir baska isim verir
print("Degisimden once a: ", a)
print("Degisimden once b: ", b)
a[2] = 3.5 # a'nin ucuncu elemanini degistirelim
print("Degisimden sonra a: ", a)
print("Degisimden sonra b: ", b) # bu nedenle a listesi degisince b listesi degisir!
c = a[:] # a listesinin elemanlarindan olusan yeni bir liste
print("Degisimden once c: ", c)
a[-1] = 4.5 # a'nin dorduncu elemanini degistirelim
print("Degisimden sonra a: ", a) # bu nedenle a listesi degisse de c listesi degismez
print("Degisimden sonra c: ", c) # bu nedenle a listesi degisse de c listesi degismez
d = a.copy()
a[0] = 0.5 # a'nin dorduncu elemanini degistirelim
print("Degisimden sonra a: ", a) # bu nedenle a listesi degisse de c listesi degismez
print("Degisimden sonra d: ", d) # bu nedenle a listesi degisse de d listesi degismez
Degisimden once a:  [1, 2, 3, 4]
Degisimden once b:  [1, 2, 3, 4]
Degisimden sonra a:  [1, 2, 3.5, 4]
Degisimden sonra b:  [1, 2, 3.5, 4]
Degisimden once c:  [1, 2, 3.5, 4]
Degisimden sonra a:  [1, 2, 3.5, 4.5]
Degisimden sonra c:  [1, 2, 3.5, 4]
Degisimden sonra a:  [0.5, 2, 3.5, 4.5]
Degisimden sonra d:  [1, 2, 3.5, 4.5]

Listelere Uygulanabilen Bazı Fonksiyonlar

Aşağıda listeler üzerinde işlem yapılmasını ve listelere ilişkin bazı bilgilerin alınmasını sağlayan bazı fonksiyonlar örnekler ile anlatılmıştır.

In [12]:
a = [10, 5, 8, -6, 21, 44, 51, -12.0, 3]
print("a listesi: ", a)
print("a listesinin uzunlugu: {:d}".format(len(a))) # a listesinin uzunlugunu veren fonksiyon
print("a listesinin minimumu: {:.2f}".format(min(a))) # a listesinin minimumunu veren fonksiyon
print("a listesinin maksimumu: {:.2f}".format(max(a))) # a listesinin maksimumunu veren fonksiyon
print("a listesinin elemanlarının toplami: {:.2f}".format(sum(a))) # a listesinin elemanlarinin toplami
print("a listesinin sirali hali: ", sorted(a)) # a listesinin elemanlarinin siralanmis hali
print("a listesinin tersi: ", list(reversed(a))) # a listesinin tersi
# son fonksiyonun (reversed) sadece listeye donusturulebilir bir nesne urettigine 
# ve list fonksiyonuyla donusum yapildigina dikkat ediniz!
a listesi:  [10, 5, 8, -6, 21, 44, 51, -12.0, 3]
a listesinin uzunlugu: 9
a listesinin minimumu: -12.00
a listesinin maksimumu: 51.00
a listesinin elemanlarının toplami: 124.00
a listesinin sirali hali:  [-12.0, -6, 3, 5, 8, 10, 21, 44, 51]
a listesinin tersi:  [3, -12.0, 51, 44, 21, -6, 8, 5, 10]

For Döngüleri

$for$ döngüsü, döngü yapısı içerisinde yer alan ifadeleri önceden istenen kadar sayıda (defa) çalıştırır.

Örnek: Amacımız verilen bir listenin tüm elemanlarını Fahrenheit dereceye çevirip ekrana yazdırmak olsun.

Algoritma:
$C = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 30, 35, 40]$
Her bir $C[index]$ elemanı için
          F = (9 / 5.) * $C[index]$ + 32
          C ve F'yi ekrana yazdır
          Bir sonraki elemana geç

Döngü içerisinde çalışmasıı istenen tüm ifadeler içeri doğru aynı miktarda bloklanmalıdır. Bir zorunluluk olmamakla birlikte, standart olarak \"<TAB\"> ya da 4 boşluk kulllanılmaktır.

In [13]:
print("------------------") # tablo basligi)
C = [-20, -15, -10, 0, 5, 10, 15, 20, 25, 30, 35, 40]
for eleman in C: # C'deki her bir eleman icin
    # for dongusune giris
    # for dongusunun icinde yapilacaklar
    F = (9.0/5)*eleman + 32 # Fahrenheit'e donusum yap
    print(eleman, F) # Ekrana yazdır
    # for dongusunden cikis
# for dongusunun disinda yapilacaklar
print("------------------") # Dongu sonrasi tablo sonu
print("elemanin dongu disindaki degeri: ", eleman)
------------------
-20 -4.0
-15 5.0
-10 14.0
0 32.0
5 41.0
10 50.0
15 59.0
20 68.0
25 77.0
30 86.0
35 95.0
40 104.0
------------------
elemanin dongu disindaki degeri:  40

Bu örnekte verilen tablo, yapısı itibarı ile bir tablo gibi düzenli görünmemektedir. Daha düzenli bir görünüm için aşağıdaki kod bloğunu kullanmak daha uygundur.

In [14]:
print("------------------") # tablo basligi
C = [-20, -15, -10, 0, 5, 10, 15, 20, 25, 30, 35, 40]
print("    C     F")
for eleman in C: # C'deki her bir eleman icin
    F = (9.0/5)*eleman + 32 # Fahrenheit'e donusum yap
    print("{:5d} {:5.1f}".format(eleman, F)) # Ekrana yazdır
print("------------------") # Dongu sonrasi tablo sonu
------------------
    C     F
  -20  -4.0
  -15   5.0
  -10  14.0
    0  32.0
    5  41.0
   10  50.0
   15  59.0
   20  68.0
   25  77.0
   30  86.0
   35  95.0
   40 104.0
------------------

Döngüler ve Listeler

range Fonksiyonu

$range(son, [baslangic], [adim])$ özellikle for döngüleri ile sıkça kullanılan ve bir sayı dizisi üreten fonksiyondur. Yaptığı iş, başlangıç değerinin verilmemesi durumunda 0'dan başlayarak verilen son değere ($stop$) kadar (son hariç!) tam sayılardan oluşan bir dizi (range) nesnesi oluşturmaktır. İstenen adım büyüklüğünün sağlanması durumunda bu adım büyüklüğü dahilinde son değere arttırarak (pozitif adım) ya da azaltarak (negatif adım) gider. Hem başlangıç ($start$), hem de adım ($step$) argümanları opsiyonel olup, fonksiyona sağlanmamaları durumunda sırasıyla 0 ve 1 varsayılan değerlerini alırlar. Python 2.x'te $range()$ verilen parametreler dahilinde bir liste oluşturan bir fonksiyondu. Buna karşılık $xrange$ ise sırayla tam sayı üreten bir dizi nesnesi oluşturuyordu. Python 3.x ile birlikte $xrange$ artık kullanılmazken $range$ onun yerini almıştır.

$$range(n) → 0, 1, 2, 3, …, n-1$$$$range(5) → 0, 1, 2, 3, 4$$$$range(3, 27, 6) → 3, 9, 15, 21$$$$range(2,8) → 2, 3, 4, 5, 6, 7$$$$range(10, 2, -2) → 10, 8, 6, 4$$

$range$ ile oluşturulan diziyi bir listeye dönüştürmek için ise $list()$ fonksiyonu kullanılır.

In [15]:
print("------------------") # tablo basligi
print("    C     F")
C = list(range(-20, 41, 5))		# C listesini olustur
F = [0.0]*len(C) # C listesiyle ayni uzunlukta sadece sifirlardan olusan bir liste olustur
for indeks in range(len(C)): # C'yi indeks uzerinden tara
    F[indeks] = (9.0/5)*C[indeks] + 32 # Ayni indekse karsilik gelen F degerini hesapla
    print("{:5d} {:5.1f}".format(C[indeks], F[indeks]))
print("------------------") # Dongu sonrasi tablo sonu
print(len(C))
print("Son indeks: ", indeks)
------------------
    C     F
  -20  -4.0
  -15   5.0
  -10  14.0
   -5  23.0
    0  32.0
    5  41.0
   10  50.0
   15  59.0
   20  68.0
   25  77.0
   30  86.0
   35  95.0
   40 104.0
------------------
13
Son indeks:  12

Reel Sayı Adım Kullanmak

$range$ fonksiyonu sadece tam sayı ($int$) üretir. Bu da başlangıç değeri ile son değer arasında hep tam sayı adım atmakla bizi kısıtlar. Adımlarımızın reel sayı olmasını istiyorsak bunu döngü yapısı içerisinde yapmamız gerekir.

In [16]:
C_adim = 0.5
C_baslangic = -5
n = 16 # listede istedigimiz eleman sayisi
C = [0.0]*n; F = [0.0]*n # n adet 0.0 'dan olusan birer liste
print("------------------") # tablo basligi
print("   C    F")
for i in range(n): # indeks üzerinden tarama
    C[i] = C_baslangic + i*C_adim
    F[i] = (9.0/5)*C[i] + 32
    print("{:5.1f} {:5.1f}".format(C[i], F[i]))
print("------------------") # Dongu sonrasi tablo sonu
------------------
   C    F
 -5.0  23.0
 -4.5  23.9
 -4.0  24.8
 -3.5  25.7
 -3.0  26.6
 -2.5  27.5
 -2.0  28.4
 -1.5  29.3
 -1.0  30.2
 -0.5  31.1
  0.0  32.0
  0.5  32.9
  1.0  33.8
  1.5  34.7
  2.0  35.6
  2.5  36.5
------------------

Daha önceki örneklerle aynı görüntüyü elde etmek istiyorsak, kodumuzu aşağıdaki şekilde değiştirmeliyiz.

In [17]:
C_adim = 0.5
C_baslangic = -20
C_son = 40
n = int((C_son - C_baslangic)/C_adim) + 1 # listede istedigimiz eleman sayisi
C = [0.0]*n; F = [0.0]*n # n adet 0.0 'dan olusan birer liste
print("------------------") # tablo basligi
print("   C    F")
for i in range(n): # indeks üzerinden tarama
    C[i] = C_baslangic + i*C_adim
    F[i] = (9.0/5)*C[i] + 32
    print("{:5.1f} {:5.1f}".format(C[i], F[i]))
print("------------------") # Dongu sonrasi tablo sonu
------------------
   C    F
-20.0  -4.0
-19.5  -3.1
-19.0  -2.2
-18.5  -1.3
-18.0  -0.4
-17.5   0.5
-17.0   1.4
-16.5   2.3
-16.0   3.2
-15.5   4.1
-15.0   5.0
-14.5   5.9
-14.0   6.8
-13.5   7.7
-13.0   8.6
-12.5   9.5
-12.0  10.4
-11.5  11.3
-11.0  12.2
-10.5  13.1
-10.0  14.0
 -9.5  14.9
 -9.0  15.8
 -8.5  16.7
 -8.0  17.6
 -7.5  18.5
 -7.0  19.4
 -6.5  20.3
 -6.0  21.2
 -5.5  22.1
 -5.0  23.0
 -4.5  23.9
 -4.0  24.8
 -3.5  25.7
 -3.0  26.6
 -2.5  27.5
 -2.0  28.4
 -1.5  29.3
 -1.0  30.2
 -0.5  31.1
  0.0  32.0
  0.5  32.9
  1.0  33.8
  1.5  34.7
  2.0  35.6
  2.5  36.5
  3.0  37.4
  3.5  38.3
  4.0  39.2
  4.5  40.1
  5.0  41.0
  5.5  41.9
  6.0  42.8
  6.5  43.7
  7.0  44.6
  7.5  45.5
  8.0  46.4
  8.5  47.3
  9.0  48.2
  9.5  49.1
 10.0  50.0
 10.5  50.9
 11.0  51.8
 11.5  52.7
 12.0  53.6
 12.5  54.5
 13.0  55.4
 13.5  56.3
 14.0  57.2
 14.5  58.1
 15.0  59.0
 15.5  59.9
 16.0  60.8
 16.5  61.7
 17.0  62.6
 17.5  63.5
 18.0  64.4
 18.5  65.3
 19.0  66.2
 19.5  67.1
 20.0  68.0
 20.5  68.9
 21.0  69.8
 21.5  70.7
 22.0  71.6
 22.5  72.5
 23.0  73.4
 23.5  74.3
 24.0  75.2
 24.5  76.1
 25.0  77.0
 25.5  77.9
 26.0  78.8
 26.5  79.7
 27.0  80.6
 27.5  81.5
 28.0  82.4
 28.5  83.3
 29.0  84.2
 29.5  85.1
 30.0  86.0
 30.5  86.9
 31.0  87.8
 31.5  88.7
 32.0  89.6
 32.5  90.5
 33.0  91.4
 33.5  92.3
 34.0  93.2
 34.5  94.1
 35.0  95.0
 35.5  95.9
 36.0  96.8
 36.5  97.7
 37.0  98.6
 37.5  99.5
 38.0 100.4
 38.5 101.3
 39.0 102.2
 39.5 103.1
 40.0 104.0
------------------
In [18]:
# Ayni islemi alternatif bir cozum olarak while dongusuyle yapalim
C_baslangic = -20; C_adim = 0.5; C_son = 40
cent = C_baslangic
C = []; F = []
print("------------------") # tablo basligi
print("   C    F")
while cent <= C_son:
    C.append(cent)
    fahr = (9.0/5)*cent + 32
    F.append(fahr)
    print("{:5.1f} {:5.1f}".format(cent, fahr))
    cent += C_adim
print("------------------") # Dongu sonrasi tablo sonu
print("cent'in son degeri: ", cent)
------------------
   C    F
-20.0  -4.0
-19.5  -3.1
-19.0  -2.2
-18.5  -1.3
-18.0  -0.4
-17.5   0.5
-17.0   1.4
-16.5   2.3
-16.0   3.2
-15.5   4.1
-15.0   5.0
-14.5   5.9
-14.0   6.8
-13.5   7.7
-13.0   8.6
-12.5   9.5
-12.0  10.4
-11.5  11.3
-11.0  12.2
-10.5  13.1
-10.0  14.0
 -9.5  14.9
 -9.0  15.8
 -8.5  16.7
 -8.0  17.6
 -7.5  18.5
 -7.0  19.4
 -6.5  20.3
 -6.0  21.2
 -5.5  22.1
 -5.0  23.0
 -4.5  23.9
 -4.0  24.8
 -3.5  25.7
 -3.0  26.6
 -2.5  27.5
 -2.0  28.4
 -1.5  29.3
 -1.0  30.2
 -0.5  31.1
  0.0  32.0
  0.5  32.9
  1.0  33.8
  1.5  34.7
  2.0  35.6
  2.5  36.5
  3.0  37.4
  3.5  38.3
  4.0  39.2
  4.5  40.1
  5.0  41.0
  5.5  41.9
  6.0  42.8
  6.5  43.7
  7.0  44.6
  7.5  45.5
  8.0  46.4
  8.5  47.3
  9.0  48.2
  9.5  49.1
 10.0  50.0
 10.5  50.9
 11.0  51.8
 11.5  52.7
 12.0  53.6
 12.5  54.5
 13.0  55.4
 13.5  56.3
 14.0  57.2
 14.5  58.1
 15.0  59.0
 15.5  59.9
 16.0  60.8
 16.5  61.7
 17.0  62.6
 17.5  63.5
 18.0  64.4
 18.5  65.3
 19.0  66.2
 19.5  67.1
 20.0  68.0
 20.5  68.9
 21.0  69.8
 21.5  70.7
 22.0  71.6
 22.5  72.5
 23.0  73.4
 23.5  74.3
 24.0  75.2
 24.5  76.1
 25.0  77.0
 25.5  77.9
 26.0  78.8
 26.5  79.7
 27.0  80.6
 27.5  81.5
 28.0  82.4
 28.5  83.3
 29.0  84.2
 29.5  85.1
 30.0  86.0
 30.5  86.9
 31.0  87.8
 31.5  88.7
 32.0  89.6
 32.5  90.5
 33.0  91.4
 33.5  92.3
 34.0  93.2
 34.5  94.1
 35.0  95.0
 35.5  95.9
 36.0  96.8
 36.5  97.7
 37.0  98.6
 37.5  99.5
 38.0 100.4
 38.5 101.3
 39.0 102.2
 39.5 103.1
 40.0 104.0
------------------
cent'in son degeri:  40.5

Reel sayı adım kullanmanın bir başka yolu da $numpy$ ($arange$ ve $linspace$) ya da $itertools$ modülü fonksiyonları kullanmaktır. Bu konulara daha ilerideki derslerimizde değineceğiz.

Başa Dön

Döngü İçerisinde Liste Elemanı Değiştirmek

Bir liste içinde gezerken herhangi bir elemana geldiğimizde onu değiştirmek istiyor olalım.

In [19]:
C = list(range(-20,45,5)) # range'in urettigi nesneyi listeye cevirmeliyiz
print("Donguden once: ", C) 
for cent in C:
    cent += 5
print("Donguden sonra: ", C)
print("cent'in son degeri: ",cent)
Donguden once:  [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
Donguden sonra:  [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
cent'in son degeri:  45

İstedğimiz şey $C$'deki her elemanı 5 arttırmaktı ama istediğimizi yapamadık. Çünkü $cent$ değişkeni bizi $C$'de sadece “gezdirir”, $C$'deki değerler üzerinde bir etkisi yoktur. İstediğimize aşağıdaki şekilde ulaşabiliriz.

In [20]:
C = list(range(-20,45,5)) # range'in urettigi nesneyi listeye cevirmeliyiz
print("Donguden once: ", C) 
for i in range(len(C)):
    C[i] += 5 # C'nin her bir degerine 5 ekle
print("Donguden sonra: ", C)
Donguden once:  [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
Donguden sonra:  [-15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45]

enumerate Fonksiyonu

Aslında bir döngü içerisinde rastlanan bir liste elemanının hem değerini hem de indeksini kullanmanın oldukça basit bir yolu var: $enumerate()$ fonksiyonu size bu olanağı sağlamaktadır.. $enumerate()# fonksiyonu bir dizi nesnesinin (range, list, tuple, array, ...) hem indeks, hem de eleman üzerinden taranabilmesi ve istendiği anda nesnenin herhangi bir elemanının değeri ile birlikte dizide bulunduğu yeri (indeks) edinilebilmesi kolaylığı sağlar.

In [21]:
C = list(range(-20,45,5))
print("Donguden once: ", C) 
for i, cent in enumerate(C):
    C[i] = cent + 5 # C'nin her bir degerine 5 ekle
print("Donguden sonra: ", C)
Donguden once:  [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
Donguden sonra:  [-15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45]

Bir listeyi ihtiyaca uygun olarak listenin elemanları, indeksi ya da her ikisi üzerinden tarayabilirsiniz. Liste icinde tarama islemleri icin pythonik yol eleman ve enumerate() fonksiyonunun kullanildigi yontemlerdir.

Özet: For döngülerini taramak için kullanılan üç ana yapı:

Eleman üzerinden tarama: for eleman in liste:
İndeks üzerinden tarama: for i in range(len(liste)):
Her ikisi üzerinden tarama: for i,eleman in enumerate(liste):

In [22]:
# Bir listeyi hem indeks, hem eleman, 
# hem de enumerate kullanarak ikisinin birden
# uzerinden tarayabilirsiniz
a = ['AST415', 3, 7.5, ['m', 'n', 'o'], -1]
indeks = 0
for eleman in a:
    print(indeks, eleman)
    indeks += 1
print('======================')
for indeks in range(len(a)):
    print(indeks, a[indeks])
print('======================')
for indeks, eleman in enumerate(a):
    print(indeks, eleman)
0 AST415
1 3
2 7.5
3 ['m', 'n', 'o']
4 -1
======================
0 AST415
1 3
2 7.5
3 ['m', 'n', 'o']
4 -1
======================
0 AST415
1 3
2 7.5
3 ['m', 'n', 'o']
4 -1

Listelerle Hızlı ve Kompakt İşlemler: List Comprehensions

Bir liste içinde gezerken her bir eleman için başka bir liste içerisinde yeni bir eleman yaratmak çok sık ihtiyaç duyulan bir özelliktir. Python bunun için list comprehensions adı verilen kompakt bir yazım kuralına sahiptir.

In [23]:
n = 10 # Listede istenen eleman sayisi olsun
C = [-5 + i*0.5 for i in range(n)]
F = [(9.0/5)*cent + 32 for cent in C]
C_arti_5 = [cent + 5 for cent in C]
print("C: ", C)
print("F: ", F)
print("C_arti_5: ", C_arti_5)
C:  [-5.0, -4.5, -4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5]
F:  [23.0, 23.9, 24.8, 25.7, 26.6, 27.5, 28.4, 29.3, 30.2, 31.1]
C_arti_5:  [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]

Birden fazla (aynı uzunlukta) liste içinde aynı anda “gezebilmek” de mümkündür.

In [24]:
n = 8
C = [-5 + i*0.5 for i in range(n)]
F = [(9.0/5)*cent + 32 for cent in C]
print("------------------") # tablo basligi
print("   C    F")
for i in range(len(C)):
    print("{:5.1f} {:5.1f}".format(C[i], F[i]))
print("------------------")
------------------
   C    F
 -5.0  23.0
 -4.5  23.9
 -4.0  24.8
 -3.5  25.7
 -3.0  26.6
 -2.5  27.5
 -2.0  28.4
 -1.5  29.3
------------------

İndeksler yerine liste elemanları kullanarak “gezmek” daha “Pythonik” 'bir yoldur.

In [25]:
a = ["x", "y", "z"]
# a listesinin icerigini ekrana sirayla getirmek icin
for i in range(len(a)):
    print("harf: ", a[i])
print("------------------")
# yerine asagidaki daha Pythonik bir yol olarak tercih edilmelidir
for harf in a:
    print("harf: ", harf)
print("------------------")
# indekse de ihtiyaciniz varsa enumerate kullanilmalidir
for i,harf in enumerate(a):
    print(i,harf)
harf:  x
harf:  y
harf:  z
------------------
harf:  x
harf:  y
harf:  z
------------------
0 x
1 y
2 z

zip Fonksiyonu

İki listeyi aynı indekse sahip karşılıklı elemanlarını yan yana getirerek birleştiren (ve bir zip nesnesi oluşturan) önemli ve kullanışlı bir fonksiyondur. $zip()$ fonksiyonu ile oluşturulan $zip$ nesnesi istendiğinde $list()$ fonksiyonu ile listeye dönüştürülebilir.

In [26]:
n = 6
C = [-5 + i*0.5 for i in range(n)]
F = [(9.0/5)*cent + 32 for cent in C]
print("------------------") # tablo basligi
print("   C    F")
for cent, fahr in zip(C, F):
    print("{:5.1f} {:5.1f}".format(cent, fahr))
print("------------------")
print("[(C, F)]: ", list(zip(C,F)))
------------------
   C    F
 -5.0  23.0
 -4.5  23.9
 -4.0  24.8
 -3.5  25.7
 -3.0  26.6
 -2.5  27.5
------------------
[(C, F)]:  [(-5.0, 23.0), (-4.5, 23.9), (-4.0, 24.8), (-3.5, 25.7), (-3.0, 26.6), (-2.5, 27.5)]

İç İçe Listeler: Nested Lists

Elemanlarından en az biri bir liste olan listeler de tanımlamak Python'nda mümkündür.

In [27]:
C = list(range(-20,41,5))
F = [(9.0/5)*cent + 32 for cent in C]
tablo1 = [C, F]
print(tablo1)
print(len(tablo1))
print(tablo1[0]) # tablo listesinin birinci elemani C listesi iken
print(tablo1[0][2]) # C listesinin ucuncu elemanina ulasir
print(tablo1[1][-1]) # F listesinin son elamanina ulasir
[[-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40], [-4.0, 5.0, 14.0, 23.0, 32.0, 41.0, 50.0, 59.0, 68.0, 77.0, 86.0, 95.0, 104.0]]
2
[-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40]
-10
104.0

Yapmak istediğimiz her bir elemanı bir liste olan yeni bir liste yerine, bir satırındaki birinci elemanını bir listeden, ikinciyi diğer listeden alan bir tablo oluşturmak ise izleyeceğimiz yol aşağıdaki gibi olmalıdır.

In [28]:
C = list(range(-20,41,5))
F = [(9.0/5)*cent + 32 for cent in C]
tablo2 = []
for cent, fahr in zip(C, F):
    tablo2.append([cent,fahr])
print(tablo2)
print(tablo2[0]) # bu durumda tablo listesinin birinci elemani ilk C, F ikilisidir.
print(tablo2[0][1]) # bu elemanin ikinci elemanina (F'ye) ulasir
[[-20, -4.0], [-15, 5.0], [-10, 14.0], [-5, 23.0], [0, 32.0], [5, 41.0], [10, 50.0], [15, 59.0], [20, 68.0], [25, 77.0], [30, 86.0], [35, 95.0], [40, 104.0]]
[-20, -4.0]
-4.0

Demet: Tuple Nesneleri

Demet nesnesi, liste nesnesine çok benzeyen bir türdür. İçeriği "sabit" listeler olarak değerlendirilebilirler ve listlerdeki '[ ]' işaretleri yerine '( )' işaretleri kullanılarak tanımlanırlar.

In [29]:
t = (2, 4, 6, "AST415.pdf") # t adinda bir demet nesnesi olusturalim
t = t + (-1.0, -2.0) # Bu demet degiskenin ucuna bir baska demet nesnesi ekleyelim
print("t: ", t)
t:  (2, 4, 6, 'AST415.pdf', -1.0, -2.0)

Bu örnekte t $tuple$ (demet) değişkeni değiştiriliyor gibi görünse de gerçekte olan şudur: $t$ adı verilen bir demet değişkenle $(-1.0, 2.0)$ demet değişkeni toplanmakta (ucuca eklenmekte), bunun sonucunda yeni bir tuple (demet) değişken oluşmaktadır. Bu yeni demet değişkene de $t$ ismi verildiği için $t$ isimli eski değişken yok olmaktadır. Yani t değişmemekte, yeni bir t oluşturulmaktadır! İndeksleme ve dilimleme de tıpkı listelerde olduğu gibidir.

In [30]:
t1 = (2, 4, 6, "AST415.pdf") # t adinda bir demet nesnesi olusturalim
t2 = t1[2:]
print("6, t1 nesnesinin bir elemani midir?: ", 6 in t1) # 6 t1'in bir elemani midir?
print("6, t2 nesnesinin bir elemani midir?: ", 6 in t2) # 6 t2'nin bir elemani midir?
print("2, t1 nesnesinin bir elemani midir?: ", 2 in t1) # 2 t1'nin bir elemani midir?
print("2, t2 nesnesinin bir elemani midir?: ", 2 in t2) # 2 t2'nin bir elemani midir?
6, t1 nesnesinin bir elemani midir?:  True
6, t2 nesnesinin bir elemani midir?:  True
2, t1 nesnesinin bir elemani midir?:  True
2, t2 nesnesinin bir elemani midir?:  False
In [31]:
print(t1[1])
for i, eleman in enumerate(t):
    print(i,eleman)
4
0 2
1 4
2 6
3 AST415.pdf
4 -1.0
5 -2.0

Demet nesenleri, liste nesnelerinde olduğu gibi nesneye eleman ekleyecek ($append$), çıkaracak ($remove$), ya da eleman değiştirecek metotlara sahip değildirler. Çünkü liste nesneleri değiştirilebilir (mutable) iken, demet nesneler değiştirilemezdir (immutable).

In [32]:
t = (2, 4, 6, "AST415.pdf")
t.append(0)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-32-6fa10a136322> in <module>
      1 t = (2, 4, 6, "AST415.pdf")
----> 2 t.append(0)

AttributeError: 'tuple' object has no attribute 'append'
In [33]:
t = (2, 4, 6, "AST415.pdf")
t.remove(6)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-33-1585761a7027> in <module>
      1 t = (2, 4, 6, "AST415.pdf")
----> 2 t.remove(6)

AttributeError: 'tuple' object has no attribute 'remove'
In [34]:
# Liste degiskenleri degistirilebilir! (mutable)
t = [2, 4, 6, "AST415.pdf"]
t[1] = -6
print(t)
[2, -6, 6, 'AST415.pdf']
In [35]:
# Demet degiskenler degistirilemez! (immutable)
t = (2, 4, 6, "AST415.pdf")
t[1] = -6
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-35-53723ac2d5e3> in <module>
      1 # Demet degiskenler degistirilemez! (immutable)
      2 t = (2, 4, 6, "AST415.pdf")
----> 3 t[1] = -6

TypeError: 'tuple' object does not support item assignment
In [36]:
t = (2, 4, 6, "AST415.pdf")
del t[1]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-469a4f188e22> in <module>
      1 t = (2, 4, 6, "AST415.pdf")
----> 2 del t[1]

TypeError: 'tuple' object doesn't support item deletion

Madem listeler daha yetenekli ve onlarla daha çok şey yapabiliyoruz, neden demet değişkenlere ihtiyaç duyuyoruz?

  1. Demet değişkenler içeriklerinin yanlışlıkla silinmesinden bizi korur!
  2. Listelere dayalı kodlar demet nesnelerine dayalı kodlardan yavaş çalışır.
  3. Karşılaştığınız pek çok kodda demet nesnesi kullanılmıştır. O kodları anlamak ve kullanmak için demet değişkenleri de öğrenmeniz gerekir!

Başa Dön

Alıştırmalar

  1. Fahrenheit derece cinsinden 0, 10, 20, ... , 100 şeklinde verilen sıcaklıkları santigrat dereceye dönüştürerek bir tablo halinde ekrana yazdıran bir program yazınız.

  2. Fahrenheit dereceyi santigrat dereceye hızlı dönüştürmek için C = (F - 30) / 2 formülü sıklıkla kullanılır. Standart Fahrenheit - Santigrat derece dönüşüm formülünün yanı sıra bu formülü de kullanarak Fahrenheit derece cinsinden 0, 10, 20, ... , 100 şeklinde verilen sıcaklıkları santigrat dereceye dönüştürerek üç sütunlu (birinci sütun F$^{\circ}$, ikinci ve üçüncü sütun iki ayrı fomülle hesaplanmış C$^{\circ}$) içerecek şekilde) bir tablo halinde ekrana yazdıran bir program yazınız.

  3. 20'den küçük tüm asal sayıları (2, 3, 5, ... , 19) bir liste oluşturup, bir for döngüsü içerisinde bu listenin elemanlarını sırayla ekrana yazdıran bir program yazınız.

  4. 1'den n = 100'e kadar tam sayıları bir listeye aldıktan sonra, bu listedeki her bir sayı için o sayıya (n) kadarki tüm sayıların toplamını Gauss'un meşhur $n*n(+1) / 2$ formülüyle hesaplayan ve yeni bir listeye yazdıran bir program yazınız.

  5. x ekseni üzerinde $[a, b]$ kapalı aralığında n+1 tane birbirinden eşit uzaklıkta koordinat içeren bir liste oluşturunuz. İpucu: Öncelikle boş bir liste oluşturup, a ile b arasında herhangi ardışık iki koordinatın arasının ne büyüklükte (h = (b - a) / n) olacağını hesapladıktan sonra bu listeyi bir for döngüsünün içinde doldurunuz.

  6. $q = [["a", "b", "c"], ["d", "e", "f"], ["g", "h"]]$ listesinden $a$ harfini, $["d", "e", "f"]$ listesini, q listenin son elemanını ve $g$ harfini verebilecek ikişer ayrı indeksleme öneriniz.

  7. Altıncı (6.) soruda verilen q listesinin tüm harflerini sırayla (her satıra bir harf) ekrana yazdıran bir döngü (ipucu: içiçe döngü) yazınız.

Başa Dön