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

Ders - 08 Veri Girişi ve Hata Yönetimi

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

Kullanıcıyla Terminal Aracılığıyla İletişim

Santigrad dereceyi Fahrenheit dereceye çeviren fonksiyonumuzu hatırlayalım. Bu fonksiyonu çağırırken istediğimiz değer(ler)i kaynak kodun içerisinden göndermek yerine kullanıcının girmesine izin verecek bir yapı işimizi oldukça kolaylaştırır ve kaynak kodumuzu farklı her değer için değiştirmemizi de önler. Bu tür bir yapıyı $input$ fonksiyonunu kullanarak kurabiliriz. $input$ fonksiyonu metin değişken döndürdüğünden bu değişkeni ihtiyaca göre diğer değişken tiplerine ($int$, $float$, $list$, $tuple$ …) çevirmek gerekebilir.

In [ ]:
def F(C):
    return (9.0/5)*C + 32
sant = input('C=? ') 
sant = float(sant)
fahr = F(sant)
print(fahr)

eval Fonksiyonu

$eval$ fonksiyonu bir metin değişkeni alıp, bir Python ifadesi şekinde yorumlar.

In [ ]:
r = eval('1 + 2')
print(r, type(r))
r = eval('"Bu Python bir harika dostum!"')
print(type(r))
r = eval('[1, 6, 7.5]')
print(r, type(r))
from math import sqrt
r = eval('sqrt(2)')
print(r, type(r))

input ile eval Ortaklığı

$eval$ fonksiyonu sadece metin değişken döndüren $input$ fonksiyonu ile kullanıcı tarafından girilen verinin herhangi bir tür değiştirme işlemine gerek kalmaksızın yorumlanmasını sağladığından oldukça pratiktir.

In [ ]:
i1 = eval(input('Birinci sayi: '))
i2 = eval(input('Ikinci sayi: '))
r = i1 + i2
print('{:} + {:} toplami {:}\ndegeri ise {:.2f}'.format(type(i1), type(i2), type(r), r))

$eval$ fonksiyonunun bir diğer kullanışlılığı kullanıcının formül girmesine ve girilen formülün bir Python ifadesi olarak yorumlanmasına imkan sağlamasıdır.

In [ ]:
# butun matemtaik fonksiyonlarini indirelim ki kullanicinin
# girebilecegi her fonksiyona hazirlikli olalim.
from math import *
formul = input('x degiskenini iceren bir formul giriniz: ')
x = eval(input('x = '))
sonuc = eval(formul)
print('x={:g} icin {:s} = {:g}'.format(x, formul, sonuc))

exec Fonksiyonu

Kullanıcı tarafından girilen bir formülü bir Python fonksiyonu olarak kullanmamızı sağlayan fonksiyondur.

In [ ]:
formul = input('x degiskenini iceren bir formul giriniz: ')
kod = """
def f(x):
    return {:s}
""".format(formul)
exec(kod)
x = eval(input('x ='))
print(f(x))

Bu programın yaptığı iş kullanıcıdan aldığı ve sadece $x$ bağımsız değişkenini içeren herhangi bir ifadeyi bir Python fonksiyonuna cevirip döndürmektir. Söz konusu Python fonksiyonu $kod$ metin (string) değişkeni içerisinde oluşturulmaktadır. $exec$ fonksiyonu bu değişkenin içeriğini bir Python ifadesi olarak çalıştırmaktadır. İçerik bir fonksiyon tanımı olduğundan bu şekilde bir f(x) fonksiyonu tanımlanmış olur. Tanımlanan fonksiyon $sin(x).cos(3x) + x^{2}$ olduğunda örnekte verilen fonksiyon ile özdeştir.

Başa Dön

Komut Satırından Girdi Almak

Pek çok linux programı kullanıcıdan girdi (input) almak üzere komut satırını kullanır. Kullanıcı programın adının hemen arkasına programda kullanılacak girdi parametresinin değerini de girer. Girdi parametresi program tarafından bir salt metin değişkenine (string) atanır ve gerekli dönüşümler ve işlemler yapıldıktan sonra program çıktısını tekrar ekrana verir.

Bunun için $sys$ modülünde tüm komut satırı parametrelerini saklayan $argv$ listesi kullanılır. Bu listenin ilk elemanı ($argv[0]$) programın adıdır. İkinci eleman ($argv[1]$) ilk parametreyi, daha sonra gelen elemanlarsa sırayla diğer parametreleri saklar.

Bu bölümde yazılacak kodları ancak komut satırından (ya da jupyter'da %run "sihirli" sözcüğünü (magic word) kulllanarak) çaıştırabileceğiniz için kodların bir metin editörü ile .py uzantılı bir dosyaya yazılmış olması gerekir. Bu nedenle bu bölümde kullanılacak kodlar ders08_ornek_kodlar.tar.gz isimli bir sıkıştırılmış dosyada toplanmıştır. Bu dosyayı indirip, sıkıştırılmış dosyadaki klasörü (ders08_ornek_kodlar) kodları çalıştıracağınız yere (path) kopyalamanız durumunda aşağıdaki örnekler çalışacaktır.

Örneğin Fahrenheit dereceye dönüştürmek istediğimiz santigrad derece değerini kullanıcıdan komut satırı yoluyla girmesini istiyor olalım. Bunun için gerekli kod ders08_ornek_kodlar/ders08_orn01_C2F.py dosyasında bulunmaktadır. Kodu açıp inceleyiniz. Bu kodu Python 3.x çalıştıran herhangi bir terminalden

$ python ders08_orn01_C2F.py 25

komutu ile çalıştırabilecğeiniz gibi %run jupyter sihirli sözcüğüyle de çalıştırabilirsiniz. 25 burada Fahrenheit dereceye dönüştürmek istediğiniz sıcaklık değeri olup, istediğniz başka bir değeri de programa argüman olarak geçirebilirsiniz.

In [5]:
%run ders08_ornek_kodlar/ders08_orn01_C2F.py 25
77.0

Örnek: Dikey Atış Problemi

Bir başka örnekte dikey atış probleminin parametrelerini kullanıcıdan komut satırı yoluyla almak üzere bir program yazmak istiyor olalım.

In [8]:
%run ders08_ornek_kodlar/ders08_orn02_dikeyatis.py 0.6 5
1.2342

Bu durumda iki komut satırı argümanına ihtiyaç duyarız, sırasıyla bu argümanların değerleri $t$ ($argv[1]$) ve $v0$ ($argv[2]$) değişkenlerine salt metin olarak atanır. Bu değişkenlerin reel sayı olmasını istediğmiz için onları $float$ fonksiyonunu kullanarak öncelikle dönüştürmemiz gerekir. Daha sonra cismin düşey konumunu hesaplar ve ekrana yazdıırırız.

Başa Dön

Belirsiz Sayıda Komut Satırı Argümanıyla Çalışmak

Bazen sayısı tam olarak bilinmeyen komut argümanıyla da çalışmak gerekbilir. Örneğin kullanıcının girdiği tüm (sayısı belirsiz) sayıları toplayan ve sonucu ekrana gerien bir kod yazmak istiyor olalım.

In [18]:
 %run ders08_ornek_kodlar/ders08_orn03_toplama.py 3.2 -2.6 0.1 9.4 -4 
Verilen 
3.2
-2.6
0.1
9.4
-4
sayilarinin toplami 6.1

Alternatif olarak aynı kodu isterseniz liste özelliklerini kullanarak çok daha kısa yazabilirsiniz.

In [23]:
 %run ders08_ornek_kodlar/ders08_orn04_toplama2.py 3.2 -2.6 0.1 9.4 -4 
Verilen 3.2 -2.6 0.1 9.4 -4 sayilarinin toplami 6.1

argüman ve değer İkilileri

Şu ana kadar gördüğünüz tüm komut satırından girdi parametreleri kullanıcının doğru sırada bu parametreleri girmesine bağlı olarak değer alırlar. Oysa ki (ls, cp, mv gibi başka Linux programlarında gördüğümüz gibi programın kullanıcının istenen parametreleri doğru sırada girmesinden bağımsız olarak -arguman = deger ikilileri ile çalışması çok iyi bir fikirdir.

Örnek olarak ivmeli bir hareketteki toplam yer değiştirmenin bulunması problemini ele alalım.

$$ s(t) = s_0 + v_0 t + \frac{1}{2} a t^2 $$

İstenirse bu kod tüm parametreler için birer değer girilerek aşağıdaki şekilde çalıştırılabileceği gibi her bir parametrenin varsayılan değeri bilindiğinden sadece bazı parametrelerin değerleri girilip, diğer parametreler için varsayılan değerler kullanılarak da çalıştırılabilir.

In [31]:
%run ders08_ornek_kodlar/ders08_orn05_yerdegistirme.py --s0 5 --v0 3 --t 2 --a 2
Toplam yer degistirme = 15

Bu kodu şimdi sadece zaman parametresini (t) 5 saniye olarak komut satırından sağlamak suretiyle diğer parametreleri varsayılan değerlerinde (s0 = v0 = 0, a = 1) varsayarak çalştıralım ve cismin 5 saniye sonraki konumunu bu şekilde hesaplayalım.

In [32]:
%run ders08_ornek_kodlar/ders08_orn05_yerdegistirme.py --t 5
Toplam yer degistirme = 12.5

Hiçbir parametre için değer sağlamaz ve opsiyon ifadesini boş bırakırsak bu kez program tüm parametreler için varsayılan değerlerle (s0 = v0 = 0, t = a = 1) çalışacaktır.

In [33]:
%run ders08_ornek_kodlar/ders08_orn05_yerdegistirme.py
Toplam yer degistirme = 0.5

Python'da Hata Yönetimi

Diyelim ki kullanıcı programımızı çalıştırırken vermesi gereken bir komut satırı argümanını unuttu. Bu durumda $argv$ listesinin ulaşmaya çalıştığımız elemanı boş kalacağından IndexError: list index out of range şeklinde bir hata mesajı alır. Zira sadece programın adı girildiğinden $argv[0]$ doludur, ancak $argv[1]$ elemanı bulunmamaktadır.

Verilen hata mesajı bizim için açıklayıcı olsa da kullanıcı için olmayabilir. Kullanıcıya aşağıdaki şekilde bir mesajla hatasını söyleyip, yönlendirebiliriz. $sys.exit(1)$ programdan bir hata nedeniyle çıkıldığını belirtir. $sys.exit(0)$ programda bir hata olmadığı halde çıkmak için kullanılır. Bu fonksiyona verilen 0 haricindeki her şey 1 anlamına gelir.

Önce programımızı kullanıcının herhangi bir santigrad derece girdiği durum için çalıştıralım.

In [40]:
%run ders08_ornek_kodlar/ders08_orn06_C2F_v2.py 25
25C = 77.0

Şimdi kullanıcı sıcaklığı girmeyi unutmuş ya da programı doğru çalıştırmayı bilmediğinden sağlamamış olsun.

In [41]:
%run ders08_ornek_kodlar/ders08_orn06_C2F_v2.py
Fahrenheit dereceye donusmesini istediginiz santigrad derece
degerini girmediniz! Lutfen programin adindan sonra bir bosluk birakip 
sicakligi santigrad derece cisinden girerek tekrar deneyiniz!
An exception has occurred, use %tb to see the full traceback.

SystemExit: 1

try except Yöntemi

Hata yönetimine daha modern bir yaklaşım try – except yöntemini kullanmaktır. Bu yöntemi santigrad derece – fahrenheit derece dönüşüm kodumuza uyarlayabiliriz. Bu durumda da kodumuz aynı şekilde çalışacaktır.

In [50]:
%run ders08_ornek_kodlar/ders08_orn07_C2F_v3.py 25
25C = 77.0
In [44]:
%run ders08_ornek_kodlar/ders08_orn07_C2F_v3.py
Fahrenheit dereceye donusmesini istediginiz santigrad derece
degerini girmediniz! Lutfen programin adindan sonra bir bosluk birakip 
sicakligi santigrad derece cisinden girerek tekrar deneyiniz!
An exception has occurred, use %tb to see the full traceback.

SystemExit: 1

Bu yöntemde öncelikle argv listesinin birinci elemanının değeri C değişkenine atanmaya çalışılıyor (try bloku). Eğer kullanıcı komut satırı argümanı girmeyi unutmuşsa bu başarılamıyor ve kullanıcıya bir hata mesajı döndürülerek, sys.exit(1) komutu verildiği (except bloku) için programdan çıkılııyor ve bu nedenle programın gerisi çalışmıyor. Kullanıcı komut satırı argümanı girmiş ise C değişkeni değerini alıyor ve except bloğunu atlayarak çalışmaya Fahrenheit derece dönüşümünün hesabıyla devam ediyor ve ekrana çıktı verip, sonlanıyor.

Başka bir örnekle try - except yönteminin nasıl çalıştığını görelim.

In [49]:
def C2F(C):
    return 9/5*C + 32

sant = '25'
try:
    print("{:g} C = {:g} F".format(sant,C2F(sant)))
except:
    print("Fahrenheit dereceye donusmesini istediginiz santigrad derece degerini nnumerik bir deger olarak girmediniz! Lutfen sicaklik icin santigrad derece cisinden numerik bir deger girerek tekrar deneyiniz!""")
    
sant2 = 25

print("-----------------------------")

sant = '25'
try:
    print("{:g} C = {:g} F".format(sant2,C2F(sant2)))
except:
    print("Fahrenheit dereceye donusmesini istediginiz santigrad derece degerini nnumerik bir deger olarak girmediniz! Lutfen sicaklik icin santigrad derece cisinden numerik bir deger girerek tekrar deneyiniz!""")
    
Fahrenheit dereceye donusmesini istediginiz santigrad derece degerini nnumerik bir deger olarak girmediniz! Lutfen sicaklik icin santigrad derece cisinden numerik bir deger girerek tekrar deneyiniz!
-----------------------------
25 C = 77 F

Program $sant = '25'$ için çalıştırıldığında '25' bir string (metin) olduğu için hata verir ve bu nedenle $except$ bloğu çalışırken $sant2 = 25$ için çalıştırıldığında doğru bir şekilde çalışmaktadır.

Python'da Bazı Hata Türleri

IndexError Hatası: Python'da bir dizi değişkenin (liste, demet ya da metin (string)) uzunluğunun ötesinde bir elemana ulaşmaya çalışılınca Python'da bu hata “tetiklenir!”

In [1]:
veri = [1.0/i for i in range(1,10)]
veri[9]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-1-1d983ee8e456> in <module>()
      1 veri = [1.0/i for i in range(1,10)]
----> 2 veri[9]

IndexError: list index out of range

ValueError Hatası: Örneğin bir metin değişkeni noktalı sayıya çevirmek gibi mümkün olmayan dönüşümlerin denenmesi Python'da bir değer hatası tetikler.

In [2]:
C = float('21 C')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-2-7c7972c54c3f> in <module>()
----> 1 C = float('21 C')

ValueError: could not convert string to float: '21 C'

NameError Hatası: Tanımlanmamış bir değişken ismine ulaşılmaya çalışıldığında tetiklenir.

In [3]:
print(degisken_adi)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-3-395264872def> in <module>()
----> 1 print(degisken_adi)

NameError: name 'degisken_adi' is not defined

ZeroDivisionError Hatası: 0 ile bölme bu hatayı tetikler.

In [4]:
3.0 / 0
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-4-9ab62454f56b> in <module>()
----> 1 3.0 / 0

ZeroDivisionError: float division by zero

SyntaxError Hatası: Yazımda yapılabilecek herhangi bir hata bu hata türünü tetikler.

In [6]:
print "Bu Python bir harika dostum!"
  File "<ipython-input-6-515042585f30>", line 1
    print "Bu Python bir harika dostum!"
                                       ^
SyntaxError: Missing parentheses in call to 'print'

TypeError Hatası: Uygulanmak istenen İşlem ya da fonksiyona onunla uyumlu olmayan veri türü geçirildiğinde tetiklenir. Aşağıdaki örneği bir metin ve bir tam sayı için denerseniz hata vermez!

In [8]:
print("herhangi bir metin"*3.14)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-d6b2ee8f50f2> in <module>()
----> 1 print("herhangi bir metin"*3.14)

TypeError: can't multiply sequence by non-int of type 'float'

Hata Mesajı Vermek

Programda hata oluşturacak bir girdi durumunda kullanıcıya her farklı durum için açıklayıcı birer hata mesajı vermek iyi bir fikirdir. Aşağıdaki örneği inceleyelim. Sıcaklık değerini yanlışlıkla bir metin olarak verdiğimizde kodumuz bunu yorumlayıp bu duruma göre bir hata mesajı üretiyor.

In [60]:
%run ders08_ornek_kodlar/ders08_orn08_C2F_v4.py yirmibir
Santigrad derece reel ya da tam sayi olarak girilmelidir,
girdiginiz yirmibir bir metindir. Lutfen duzeltip tekrar deneyiniz!
An exception has occurred, use %tb to see the full traceback.

SystemExit: 1

Kodumuza sıcaklık değeri olarak 21 dereceyi komut satırından sağladığımızda ise kodumuz doğru olarak çalışıyor.

In [59]:
%run ders08_ornek_kodlar/ders08_orn08_C2F_v4.py 21
21C = 69.8F

Kodumuza mutlak sıfırın altında bir sıcaklık (örneğin -275 C) verildiğinde ise kodumuz kullanıcıya girdiği sıcaklık değerinin fiziksel bir sıcaklık değeri olmadığını hatırlatıyor.

In [61]:
%run ders08_ornek_kodlar/ders08_orn08_C2F_v4.py -275
C=-275 fiziksel bir deger degildir!
An exception has occurred, use %tb to see the full traceback.

SystemExit: 1

Son olarak kullanıcı bir sıcaklık değeri girmezse buna uygun bir mesaj da kod tarafından üretiliyor.

In [62]:
%run ders08_ornek_kodlar/ders08_orn08_C2F_v4.py
Komut satirinda sicaklik santigrad derece olarak girilmelidir!
An exception has occurred, use %tb to see the full traceback.

SystemExit: 1

Ödev 8

Teslim Tarihi: 2 Ocak 2020, Perşembe 12:00

Soru 1. Yaysaniyesi biriminde Gaia paralaksı ve kadir biriminde görsel bölgedeki görünen parlaklığı kullanıcı tarafından girilen bir yıldızın parsek biriminde uzaklığını ve görsel bölgedeki mutlak parlaklığını (kadir biriminde) uzaklık modülünü kullanarak hesaplayan ve ekrana yazdıran bir Python kodu yazınız. Kodunuzu

p(") = 0.068, $m_V = 5^m.46$
p(") = 0.024, $m_V = 7^m.14$
p(") = 0.0014, $m_V = 17^m.77$

yıldızları için test ediniz.

Soru 2. Kullanıcı tarafından girilen herhangi bir polinomda yine kullanıcı tarafından girilecek x değerini yerine koyarak, polinomun alacağı değeri hesaplayan bir Python kodu yazınız.

Örnek çalışma:
Kullanıcı girişi: Bir parabol denklemi giriniz: $x**2 - 5*x + 6 $
Kullanıcı girişi: x = $2$
Ekran çıktısı: Polinomun x = 2 icin degeri 0 dir.

Ödev Sorularının Cevapları

Başa Dön