3.2. Kullanıcıdan Veri Alma
Kayıt Tarihi:
Son Güncelleme:
Bu ders biraz uzun olacak, programın kullanıcı ile iletişim kurabilmesinin tüm yollarını tek bir derste açıklamak istedim. Bu yollar şunlar: programın kullanıcıya sorular sorarak veri alması, kullanıcının programı çalıştırırken komut satırından programa veri iletmesi, programın kullanıcının oluşturduğu bir dosyadan veriler alması ve programın bir dosyaya yazarak kullanıcıya veri iletmesi. Ayrıca bu derste kullanıcının hatalı veri iletmesi sonucu oluşabilecek hataları kontrol etmenin de yollarını öğreneceksiniz.
Anahtar Kelimeler: argparse · close · dosya okuma yazma · eval · exception · exec · file · hata kontrolü · indexerror · nameerror · open · raise · raw_input · read · readlines · Simpson kuralı · split · sys.argv · terminal · try-except · typeerror · valueerror · with · zerodivisionerrorYazdığımız programlarda değişkenlere yapılacak değer atamalarını kullanıcıdan almak isteyebiliriz. Bu durumda program ile kullanıcı etkileşim kurarak veri akışı sağlanmalıdır. Programın kullanıcıdan veri almasının üç temel yolu vardır. Program çalışırken gerekli olan durumlarda kullanıcıya soru sorup aldığı cevabı veri olarak işleyebilir, ya da kullanıcı Terminalden programı çalıştırırken komut satırında bazı verilerin programa aktarılmasını sağlayabilir. Diğer yöntem ise kullanıcının programa iletmek istediği verileri bir dosyada kaydetmesi ve programın bu dosyayı okumasıdır. Bu bölümde bu yöntemleri ele alacağız. Kullanıcıdan veri almanın bazı riskleri vardır, kullanıcı programın beklemediği tipte veya formatta veriler ileterek programın hata üretmesini sağlayabilir. Böyle durumları kontrol etmek için programımızda hata kontrölü yapmalıyız, bölüm içinde bu konuya da değineceğiz.
Kullanıcıya Soru Sorma
Programa kullanıcının ilettiği verilere kullanıcı girişi (user input) deriz, bir programa kullanıcı girişi sağlamanın en basit yolu programın kullanıcıya soru sormasını sağlamaktır. Python'da bu işi raw_input()
fonksiyonu ile yaparız, bu fonksiyon aldığı string
tipi argümanı ekrana yazdırarak kullanıcının klavye ile bir veri girip enter tuşuna basmasını bekler.
from math import pi
r = raw_input("Yaricap Girin: ")
r = float(r)
A = pi*r**2
print "Yaricapi %g olan daire alani: %g" % (r, A)
Bu örnekte de raw_input()
fonksiyonunun kullanımını gözlemleyin. Bu fonksiyonu çalıştırınca aşağıdaki çıktıda görüleceği gibi ekrana Yaricap Girin:
mesajı yazdırılır ve program bekler. Kullanıcı bir sayı girip enter tuşuna basınca diğer komutlar kaldığı yerden çalıştırılmaya devam eder. Burada dikkat edilmesi gereken husus şudur, raw_input()
komutu ile kullanıcıdan alınan veriler her zaman bir string nesnesi olarak alınır. Dolayısıyla bu veriyle işlem yapmadan önce bunu uygun nesnelere dönüştürmemiz gerekir, burada bunu bir float
nesnesine dönüştürdük.
Terminal > python raw1.py
Yaricap Girin: 2.75
Yaricapi 2.75 olan daire alani: 23.7583
Başka bir örnek olarak daha önce ele aldığımız $y(t)=v0t-0.5gt^2$ foksiyonunu hesaplatalım.
v0 = float(raw_input("ilk hiz= "))
t = float(raw_input("zaman= "))
g = raw_input("yer cekimi ivmesi= ")
g = float(g) if g else 9.81
y = lambda v0, t, g: v0*t - 0.5*g*t**2
print y(v0, t, g)
Bu programın çıktısı aşağıdaki gibi olur. Satır içi if
testini nasıl kurduğumuza dikkat edin. Burada dallanmayı parantez içinde yapmak zorunda olmadığımızı anlıyoruz. Ayrıca if g
ifadesinde g
nesnesini nasıl bool
nesnesi olarak kullandığımıza da dikkat edin. Hatırlayın, boş stringler False
bool değerine sahiptir. Program ilk çalıştırıldığında kullanıcı yercekimi ivmesi=
sorusuna cevap vermeden enter tuşuna basıyor, burada program cevabı boş bir string nesnesi olarak algılıyor.
Terminal > python raw2.py
ilk hiz= 2
zaman= 0.1
yer cekimi ivmesi=
0.15095
Terminal > python raw2.py
ilk hiz= 2
zaman= 0.1
yer cekimi ivmesi= 1.62
0.1919
Terminal Parametreleri
Terminal uygulamasından programlarımızı nasıl çalıştırdığımızı hatırlayalım, komut satırına python program.py
komutunu giriyorduk. Bu komutla aslında işletim sistemi komut istemcisine, python
isimli yazılımı program.py
parametresi ile çalıştırması emrini veriyoruz. Python yazılımının görevi, kendisine verilen ilk parametrede yolu belirtilen dosya içindeki komutları çalıştırıp ekranda çıktıları göstermektir. Python yazılımı birden fazla parametre ile çalıştırılıp, program isminden sonraki parametre değerlerini çalıştırdığımız programa iletebilir. Böylece kullanıcı bazı verileri, programı komut satırından çalıştırırken girerek programa iletebilir.
Python'da sys
modülü içinde argv
isimli bir list nesnesi tanımlıdır, bu listede tüm komut satırı parametreleri saklanır. sys.argv[0]
elemanı her zaman programın ismidir, sonrasında gelen elemanlar da sırasıyla diğer komut satırı parametreleridir. Yine bu parametreler de birer string
nesnesi olarak alınır, dolayısıyla uygun dönüşümler yapılarak kullanılmalıdır.
import sys
t = sys.argv[1]
t = float(t); v0 = 2; g = 9.81
y = v0*t - 0.5*g*t**2
print y
Bu örnekte de görüldüğü gibi argv
listesine erişmek için import sys
komutu ile sys
modülüne erişim sağlamalıyız. Daha sonra komut satırında program isminden sonra girilen ilk argümanı t
değişkenine atıyoruz, bu bir string verisi olacağından sonrasında bunu float
nesnesine çevirerek programa devam ediyoruz. Kullanıcı bu programı çalıştırırken program isminin arkasından bir boşluk bırakıp bir sayı yazıp enter tuşuna basmalıdır. Kullanıcı program isminden sonra bir float
nesnesine çevrilebilecek bir argüman girmezse hata oluşacaktır.
Terminal > python sysargv1.py 0.1
0.15095
Komut satırında birdan fazla arügman ile programa parametreler aktarılabilir. Kullanıcının aralarında boşluk bırakarak girdiği her veri yeni bir argüman olarak sys.argv
listesinde yerini alacaktır. Dolayısıya tüm parametrelere sys.argv[1]
, sys.argv[2]
, ve benzer şekilde erişilebilir.
import sys
g = 9.81
v0 = float(sys.argv[1])
t = float(sys.argv[2])
y = v0*t - 0.5*g*t**2
print y
Bu programı çalıştırırken kullanıcı program isminden sonra aralarında boşluk bırakarak iki sayı girmelidir. Daha az parametre girerse veya float
nesnesine çevrilemeyecek bir veri girerse program hata verecektir.
Terminal > python sysargv2.py 2 0.1
0.15095
Komut satırı argümanları girerken dikkat etmemiz gereken bir nokta var. Sistem boşluk ile ayrılmış her veriyi ayrı bir parametre olarak kaydettiğinden, boşluklar da içeren bir string
nesnesini parametre olarak girerken dikkatli olunmalıdır. Böyle bir veriyi kullanıcı tırnak işaretleri arasında girmelidir, aksi taktirde girilen metnin her bir kelimesi ayrı bir parametre olarak algılanır.
import sys
metin = sys.argv[1:]
print "girilen parametrelerin listesi:"
print metin
Bu programı çalıştırırken üç kelimeden oluşan bir string
nesnesi girelim. Bunu tırnak içinde yazmazsak her bir kelimesi ayrı bir argüman olarak değerlendirelecektir. Tek bir argüman olarak algılanmasını sağlamak için tırnak işaretleri kullanmalıyız.
Terminal > python sysargv3.py bu bir metin
girilen parametrelerin listesi:
['bu', 'bir', 'metin']
Terminal > python sysargv3.py "bu bir metin"
girilen parametrelerin listesi:
['bu bir metin']
Komut satırından varsayılan değerli argümanlar da alınabilir, bu işlem için Python'da argparse
modülü kullanılır. Bu modülün kullanımını aşağıdaki örnek üzerinde açıklayacağız.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--v0', type=float, default=2.0, help='ilk hiz')
parser.add_argument('--g', type=float, default=9.81, help='yer cekimi')
parser.add_argument('--t', type=float, default=0.1, help='zaman')
args = parser.parse_args()
v0 = args.v0
g = args.g
t = args.t
s = v0*t - 0.5*g*t**2
print s
Öncelikle argparse
modülüne erişip ArgumentParser()
komutuyla bir parser
nesnesi oluşturuyoruz, bu nesne ile tanımlanacak argümanları komut satırından okuyacağız. Daha sonra bu nesnenin üzerinde tanımlı add_argument()
komutuyla programda kullanacağımız tüm komut satrı argümanlarını tanımlıyoruz. Değişkenlerin isimlerini, tiplerini, varsayılan değerlerini ve yardım metnini örnekteki gibi gireriz. Bundan sonra bu nesnenin parse.args()
komutunu kullanarak programımızın argümanları komut satırından okuyarak args
isimli yeni bir nesne içinde saklamasını sağlıyoruz. Artık komut satırından girilen varsayılan değerli argümanlar program içinde args.v0
biçiminde erişilebilir durumdadır. Kullanıcı komut satırından bir argüman girmek isterse bunu --v0 2.0 --t 0.1 --g 9.81
biçiminde girebilir. Ayrıca argparse
modülü hazırladığımız programlarımız için bir de yardım metni oluşturur, bu metni görüntülemek için programı -h
parametresiyle çalıştırmak yeterlidir.
Terminal > python sysargv4.py
0.15095
Terminal > python sysargv4.py --g 1.62
0.1919
Terminal > python sysargv4.py --g 1.62 --t 2
0.76
Terminal > python sysargv4.py --g 1.62 --t 1 --v0 15
14.19
Terminal > python sysargv4.py -h
usage: sysargv4.py [-h] [--v0 V0] [--g G] [--t T]
optional arguments:
-h, --help show this help message and exit
--v0 V0 ilk hiz
--g G yer cekimi
--t T zaman
Eval ve Exec Fonksiyonları
Kullanıcı raw_input()
veya komut satırı argümanları aracılığıyla alınan veriler string
nesnesi olarak alınır ve daha programda hesaplamalara dahil edilmeden önce uygun nesnelere dönüştürülür. Fakat bu yolla kullanıcı örneğin pi
verisini programa aktaramaz.
>>> from math import pi
>>> s = "pi"
>>> type(s)
type 'str'>
>>> float(s)
Traceback (most recent call last):
File "", line 1, in
ValueError: could not convert string to float: pi
Böyle durumlarda eval()
(evaluate) fonksiyonundan faydalanırız. s
bir string nesnesi olmak üzere x = eval(s)
komutu Python'da x = s
kodunu çalıştırı. Dolayısıyla eğer s
string nesnesi geçerli bir Python ifadesi biçiminde bir string nesnesi ise, hatasız bir atama gerçekleşecektir.
>>> from math import pi, sqrt
>>> s1 = "pi"
>>> s2 = "sqrt(2)"
>>> x = eval(s1)
>>> x
3.141592653589793
>>> y = eval(s2)
>>> y
1.4142135623730951
eval()
fonksiyonu aldığı string argümanı önce bir Python ifadesi olarak çalıştırıp bir veriye dönüştürdükten sonra döndürür. Yukarıdaki örnekte bunu gözlemleyebiliyoruz. Benzer şekilde x = eval("1 + 2")
komutu arka planda doğrudan x = 3
komutunu çalıştırır.
from math import * # > program.py "sin(x) + sqrt(2*x)" pi
import sys
f = sys.argv[1] # f = "sin(x) + sqrt(2*x)"
x = eval(sys.argv[2]) # x = pi
y = eval(f) # y = sin(x) + sqrt(2*x)
print "y=f(x)=%s, x=%s -> y=%g" % (f, x, y)
Yukarıdaki örnekte eval()
fonksiyonunun ne kadar kullanışlı olduğunu gözlemleyebiliriz. $y=f(x)$ biçiminde bir fonksiyonun hem formülünü hem de değişken değerini kullanıcı fonksiyona sağlayabilir. Burada kullanıcı fonksiyonu komut satırında tırnak işareti içinde girmelidir çünkü parantez sembolleri komut satırı için anlamlı sembollerdir ve düz string olarak algılanmaz.
Terminal > python sysargv5.py "sin(x) + sqrt(2*x)" pi
y=f(x)=sin(x) + sqrt(2*x), x=3.14159265359 -> y=2.50663
Python'da eval()
fonksiyonuna benzer olan bir de exec()
(execute) fonksiyonu vardır. Bu fonksiyon da argüman olarak aldığı string nesnesini Python koduna çevirir fakat bu fonksiyon çok satırdan oluşan string nesnelerini de alabilir. Örneğin aşağıdaki program da yukarıda yazdığımız programla aynı çıktıyı üretir. Fakat bu program kullanıcının verdiği formülü kullanarak bir fonksiyon tanımlar.
from math import *
import sys
formul = sys.argv[1]
s = """
def f(x):
return %s
""" % formul
exec(s)
x = eval(sys.argv[2])
y = f(x)
print "y=f(x)=%s, x=%s -> y=%g" % (formul, x, y)
Başka bir örnek olarak daha önce ele aldığımız Simpson kuralı ile yaklaşık integrasyon yapan programımızı tekrar ele alalım. exec()
fonksiyonu yardımıyla kullanıcıdan verileri alabiliriz.
from math import *
import sys
def Simpson(f, a, b, n=100):
h = (b-a)/float(n); toplam1 = 0; toplam2 = 0
for i in range(1, n/2 + 1):
toplam1 += f(a + (2*i-1)*h)
for i in range(1, n/2):
toplam2 += f(a + 2*i*h)
integral = (h/3)*(f(a) + f(b) + 4*toplam1 + 2*toplam2)
return integral
formul , a, b = sys.argv[1:]
a = eval(a); b = eval(b)
s = """
def f(x):
return %s
""" % formul
exec(s)
print "f(x)=%s, a=%s, b=%s" % (formul, a, b)
for n in 2, 5, 10, 50, 100, 500, 1000:
hesap = Simpson(f, a, b, n)
kesin = 4.0/3
hata = abs(hesap - kesin)
print "n = %4d, Hesaplanan=%.12f, Hata=%g" % (n, hesap, hata)
Bu durumda kullanıcı komut satırından fonksiyonu ve integrasyon sınırlarını programa verir. Bu program da gerekli hesaplamaları yapıp aşağıdaki gibi bir çıktı üretir.
Terminal > python simpson4.py "sin(x)**3" 0 pi
f(x)=sin(x)**3, a=0, b=3.14159265359
n = 2, Hesaplanan=2.094395102393, Hata=0.761062
n = 5, Hesaplanan=1.251135387587, Hata=0.0821979
n = 10, Hesaplanan=1.332599724263, Hata=0.000733609
n = 50, Hesaplanan=1.333332289401, Hata=1.04393e-06
n = 100, Hesaplanan=1.333333268318, Hata=6.50158e-08
n = 500, Hesaplanan=1.333333333229, Hata=1.03907e-10
n = 1000, Hesaplanan=1.333333333327, Hata=6.49392e-12
Dosya Okuma ve Yazma
Programlarımızda tanımladığımız fonksiyonların argümanlarını kullanıcıdan raw_input()
metoduyla soru sorarak veya komut satırından parametre olarak almak küçük boyutlu veriler için kullanışlıdır. Fakat büyük boyutlarda veri almak için genelde verileri bir dosyada saklayıp program içinden bu dosyanın içeriğini okuruz. Benzer şekilde program çıktıları büyük verilerden oluşuyorsa print
yoluyla ekrana yazdırmak kullanışsızdır, bunun yerine çıktıyı yine bir dosyaya yazdırmak isteriz. Python'da dosya okuma ve yazma işlemlerini örnekler üzerinde açıklayacağız.
12.0
20.3
5.1
198.5
66.9
0.7
53.6
18.7
81.5
170.0
Yukarıdaki içeriğe sahip bir data1.txt
dosyamız olsun. Görüldüğü gibi dosya içeriği on satırdan oluşmakta, her satır içeriği de bir ondalıklı sayı biçimindedir. Bu gibi veri içeren dosyaları salt metin editörlerinde oluşturmalıyız, MS Word gibi metin işleyicileriyle oluşturulan dosyalar fazladan veriler içerir.
Pythonda bir dosyanın içeriğini okumanın birden fazla yöntemi vardır, bunlardan birisi dosyanın içeriğini satır satır okumaktır. Dosya okuma işlemine başlamak için bir file
(dosya) nesnesi oluşturmalıyız. Bunu dosya = open("data1.txt", "r")
komutuyla yapabiliriz. Burada ilk argüman açılacak olan dosyanın diskteki yolunu, diğer argüman ise dosyanın hangi amaçla açılacağını belirtir. Burada kullandığımız r
argümanı dosyayı okumak için (read) açtığımızı belirtiyoruz. Bu aşamadan sonra oluşturduğumuz dosya nesnesi üzerinde tanımlı olan dosya.readline()
fonksiyonu ilk kez çağırıldığında dosyanın ilk satırının tamamı bir string verisi olarak okunur, bu fonksiyon bir kez daha çağırılınca sıradaki satır okunur. Dosya okuma işlemlerimiz bittikten sonra dosya nesnesini dosya.close()
komutu ile kapatmalıyız.
dosya = open("data1.txt", "r")
s = dosya.readline()
print "satir 1: %s" % s
s = dosya.readline()
print "satir 2: %s" % s
dosya.close()
Yukarıdaki program dosyanın ilk iki satırını okuyup ekrana yazdırır, çıktısı aşağıdaki gibi olacaktır.
Terminal > python file1.py
satir 1: 12.0
satir 2: 20.3
Bu satırlarda bulunan sayılarla işlem yapmak için bunları float
nesnelerine dönüştürmemiz gerekiyor.
dosya = open("data1.txt", "r")
s1 = float(dosya.readline())
print "satir 1: %s" % s1
s2 = float(dosya.readline())
print "satir 2: %s" % s2
dosya.close()
print "Toplam: %f" % (s1 + s2)
Bu programın çıktısı da aşağıdaki gibi olacaktır.
Terminal > python file2.py
satir 1: 12.0
satir 2: 20.3
Toplam: 32.300000
Dosya içindeki tüm sayıları toplamak için özel bir döngü kullanabiliriz.
dosya = open("data1.txt", "r")
toplam = 0
for s in dosya:
toplam += float(s)
dosya.close()
print "toplam: %f" % toplam
Burada for
döngüsünün kullanımına dikkat edelim. Döngü içinde dosya
isimli nesne satırlardan oluşan bir list
nesnesi olarak kabul edilir. Bu programın çıktısı aşağıdaki gibi olacaktır.
Terminal > python file3.py
toplam: 627.300000
Başka bir örnek olarak aşağıdaki programı inceleyin.
dosya = open("data1.txt", "r")
def y(t):
return v0*t - 0.5*g*t**2
v0 = 1000; g = 9.81
for t in dosya:
t = float(t)
print "t=%5.1f, y(t)=%f" % (t, y(t))
dosya.close()
Bu program aşağıdaki çıktıyı verecektir.
Terminal > python file4.py
t= 12.0, y(t)=11293.680000
t= 20.3, y(t)=18278.698550
t= 5.1, y(t)=4972.420950
t=198.5, y(t)=5231.963750
t= 66.9, y(t)=44947.132950
t= 0.7, y(t)=697.596550
t= 53.6, y(t)=39508.131200
t= 18.7, y(t)=16984.770550
t= 81.5, y(t)=48919.763750
t=170.0, y(t)=28245.500000
Python'da dosya okumak için kullanılan başka bir komut da dosya.readlines()
komutudur. Bu komut tüm dosyayı tek seferde okuyup her satırı bir string
nesnesi olarak bir list
nesnesine kaydeder.
>>> dosya = open("data1.txt", "r")
>>> s = dosya.readlines()
>>> print s
['12.0\n', '20.3\n', '5.1\n', '198.5\n', '66.9\n', '0.7\n', '53.6\n',
'18.7\n', '81.5\n', '170.0']
>>> x = float(s[3])
>>> print x
198.5
>>> dosya.close()
Yukarıdaki interaktif Python oturumunu incelerseniz her bir satır gizli olarak dosyada \n
karakterini içeriyor, bu bir kaçış karakteridir ve nesneyi bir float
nesnesine dönüştürmemizi engellemez. Dosya okumak için kullandığımız başka bir komut ise dosya.read()
komutudur, bu komutla dosya içeriğinin tamamı tek seferde okunup tek bir string
nesnesi olarak kaydedilir. Büyük boyutlu dosyalarda bu yöntem pek önerilmez. Daha sonra istersek bu string
nesnesinin her satırını bir eleman olarak bir list
nesnesine kaydedebiliriz, bunu yapmak için string
nesneleri üzerinde tanımlanmış olan split()
fonksiyonunu kullanırız.
>>> dosya = open("data1.txt", "r")
>>> s = dosya.read()
>>> type(s)
type 'str'>
>>> print s
12.0
20.3
5.1
198.5
66.9
0.7
53.6
18.7
81.5
170.0
>>> print s.split()
['12.0', '20.3', '5.1', '198.5', '66.9', '0.7', '53.6', '18.7',
'81.5', '170.0']
>>> dosya.close()
Python'da dosya açma ve kapama işlemini daha kompakt bir kod parçası ile yapabiliriz, bunun için with
ifadesini kullanırız. Bir örnek üzerinde inceleyelim.
with open("data1.txt", "r") as dosya:
toplam = 0
for s in dosya:
toplam += float(s)
print "toplam: %f" % toplam
Burada ilk satırdaki kodlar belirtilen isimdeki dosya nesnesini oluşturur, alt satırlardaki hizalı kodlar çalıştıktan sonra da dosya nesnesi otomatik olarak kapanır. Yukarıdaki örnekteki program ile aşağıdaki program bire bir aynı işi yapar, yani birbirine denktir. Python'da dosya işlemleri yapmanın önerilen yolu with
ifadesini kullanmaktır.
dosya = open("data1.txt", "r")
toplam = 0
for s in dosya:
toplam += float(s)
dosya.close()
print "toplam: %f" % toplam
Başka bir örnek olarak aşağıdaki dosyayı ele alalım.
Weather station ANKARA/CENTRAL is at about 40.00N 32.90E.
Height about 894m above sea level.
Jan 0.0
Feb 1.2
Mar 5.3
Apr 11.1
May 15.8
Jun 19.8
Jul 23.0
Aug 22.9
Sep 18.3
Oct 12.7
Nov 7.2
Dec 2.2
Year 11.6
Dikkat edilirse bu dosyanın satırlarında hem sayılar hem de metinler bulunmaktadır. Dosyanın içeriğine değinelim, bu dosya WorldClimate internet sitesindeki verilerden derlenmiştir. Ankara şehrinin 1926 ile 1991 yılları arasındaki 784 ay boyunca günlük ortalama hava sıcaklığı ölçülmüş ve aylara göre ortalama sıcaklık değerleri hesaplanmıştır. Bu dosyada her ayın ortamala sıcaklık değeri içerilmektedir. İlk iki satırda şehir ile ilgili kısa bir bilgi sunulmuş, dosyanın son satırında ise ölçümler sonucunda şehrin yıllık ortalama sıcaklık değeri sunulmuştur. Amacımız bu dosyadaki aylara ait sıcaklık verilerini bir listeye kaydetmek, liste ile daha sonra iletişim kurarak gerekli durumlarda erişebiliriz. Aşağıdaki programla bu işlemi gerçekleştirebiliriz.
with open("data2.txt", "r") as dosya:
data = [x for x in dosya][2:-1] #gereksiz satirlari alma
aylar = []; sicakliklar = []
for satir in data:
ay = satir.split()[0] #satiri ayristir, ilk parca
sicaklik = satir.split()[1] #satiri ayristir, ikinci parca
aylar.append(ay)
sicakliklar.append(sicaklik)
for ay, sicaklik in zip(aylar, sicakliklar):
print ay, sicaklik
Bu programın stratejisi söyledir. Önce dosyanın satırlarından bir liste oluşturuyoruz fakat ilk iki ve son satırı listede kaydetmiyoruz. Bu listenin her bir elemanı bir ay ve o aya ait sıcaklık bilgisinden oluşuyor. Daha sonra iki boş liste oluşturup bu listenin elemanlarını split()
yöntemi ile parçalayıp olacak şekilde append()
metodunu kullanan bir döngü kullanıyoruz. Son olarak bu listeleri bir tablo olarak yazdırıyoruz. Programın çıktısı aşağıdaki gibi olacaktır.
Terminal > python file7.py
Jan 0.0
Feb 1.2
Mar 5.3
Apr 11.1
May 15.8
Jun 19.8
Jul 23.0
Aug 22.9
Sep 18.3
Oct 12.7
Nov 7.2
Dec 2.2
Şimdi biraz da dosyaya veri yazma konusuna değineceğiz. Python'da dosyaya veri yazmak oldukça basittir, kullanılan fonksiyon dosya.write(s)
komutudur. Bu komut dosya nesnesine s
string nesnesini yazar. Dikkat edilmesi gereken kısım bu komutla yazılan string verisinin sonunda satır atlanmaz, dolayısıyla yeni satıra geçmek için yeni satır karakteri de eklenmelidir: dosya.write(s + '\n')
. Ayrıca bu yöntemle bir dosyaya yeni baştan yazmak için dosya nesnesi dosya = open("data.txt", "w")
biçiminde açılmalıdır, eğer dosyanın sonuna ekleme yapılmak isteniyorsa dosya = open("data.txt", "a")
olarak açılmalıdır. Buradaki w
ve a
harfleri write ve append kelimelerini baş harfleridir. Burada bahsettiğimiz tüm yazma işlemleri için with
ifadesi de kullanabilir.
y = lambda t: v0*t - 0.5*g*t**2
v0 = 5; g = 9.81
tlist = [i*0.15 for i in range(5)]
with open("data3.txt", "w") as dosya:
for t in tlist:
dosya.write("y(%4.2f)=%f\n" % (t, y(t)))
Bu programın çalıştırılması sonucunda oluşan data3.txt
dosyasının içeriği aşağıdaki gibi olacaktır.
y(0.00)=0.000000
y(0.15)=0.639637
y(0.30)=1.058550
y(0.45)=1.256738
y(0.60)=1.234200
Hata Kontrolü
Daha önce yazdığımız aşağıdaki programı ele alalım.
import sys
t = sys.argv[1]
t = float(t); v0 = 2; g = 9.81
y = v0*t - 0.5*g*t**2
print y
Kullanıcı bu programı çalıştırırken bir sayıyı komut satırı argümanı olarak vermelidir. Eğer kullanıcı programı hiç bir argüman vermeden çalıştırırsa Python kullanıcıya bir hata mesajı gösterip programın çalışmasını durdurur.
Terminal > python sysargv1.py
Traceback (most recent call last):
File "sysargv1.py", line 3, in
t = sys.argv[1]
IndexError: list index out of range
Hata mesajını incelersek sysargv1.py
dosyasının 3. satırında t = sys.argv[1]
kodlarında bir hata ile karşılaşıldığı belirtiliyor. Bu hatanın tipi IndexError
, açıklaması da liste indisinin kapsam dışı olması olarak veriliyor. Python da program içinde oluşan kodlama hatalarına Exception denir. Gerçekten kodları inceleyecek olursak kullanıcı argüman girmediği için sys.argv
listesinin tek bir elemanı var o da programın ismi, bunun da indisi 0 olacağından bu liste içinde 1 indisli hiç bir eleman yoktur. Programcı açısından bu açıklama yeterli olabilir ama kullanıcı için olası hataların programın içinde tespit edilip daha uygun bir açıklama ile uyarılması daha uygun olacaktır. Bu bölümde program içinde hataların tespit edilmesi konusu işlenecektir.
Örneğin yukarıdaki gibi IndexError
hatalarını tespit etmek ve kullanıcıyı bilgilendirmek için aşağıdaki gibi bir yol izlenebilir.
import sys
if len(sys.argv) < 2:
print "Bir arguman mutlaka girilmeli.."
sys.exit(1)
t = float(sys.argv[1])
v0 = 2; g = 9.81
y = v0*t - 0.5*g*t**2
print y
Burada kullandığımız sys.exit()
fonksiyonu programın o anda durdurulmasını sağlar. Argüman olarak 1
girerek karşılaşılan bir hata sonucu programın sonlandırıldığını belirtiyoruz, bunu 0
girersek hata ile karşılaşılmadan da programı sonlandırdığımızı belirtiriz. Bu programın çıktısı aşağıdaki gibi olacaktır.
Terminal > python except1.py 0.1
0.15095
Terminal > python except1.py
Bir arguman mutlaka girilmeli..
Python'da bu hata tespit ve kontrol yönteminin daha modern ve kompakt bir yolu vardır, bu işlemler için try-except bloklarını kullanırız. Bunu bir örnek üzerinde açıklayalım.
import sys
try:
t = float(sys.argv[1])
except:
print "Komut satirindan arguman alinamadi.."
sys.exit(1)
v0 = 2; g = 9.81
y = v0*t - 0.5*g*t**2
print y
Görüldüğü gibi hata kontrolü için kullandığımız try-except
yapısı, dallanma için kullandığımız if-else
yapısına benzerdir. Burada program önce try
bloğu içindeki kodları çalıştırmayı dener, eğer sorunsuz bir şekilde bu kodlar çalışırsa program except
blokunu atlar ve 9 numaralı satırdan çalışmaya devam eder. Ama eğer try
bloğu içinde verilen kodlar çalıştırılırken bir sorun ile karşılaşılırsa program except
blokunda bulunan kodları çalıştırır.
Terminal > python except2.py 0.1
0.15095
Terminal > python except2.py
Komut satirindan arguman alinamadi..
Terminal > python except2.py 0.1saniye
Komut satirindan arguman alinamadi..
Yukarıda görülen program çıktısından da anlaşılacağı gibi sadece komut satırından argüman girilmemesi durumu söz konusu değildir. Kullanıcı komut satırından bir argüman girmiştir fakat bu veri float
nesnesine çevrilemeyen bir veridir. Böyle durumlarda ValueError
exception tipi oluşur.
Terminal > python sysargv1.py 0.1sn
Traceback (most recent call last):
File "sysargv1.py", line 4, in
t = float(t); v0 = 2; g = 9.81
ValueError: invalid literal for float(): 0.1sn
Bunların dışında sık karşılaşılan exception tipleri şöyle sıralanabilir. NameError
: tanımlanmamış bir değişken ismi ile karşılaşıldığında oluşur, ZeroDivisionError
: sıfır ile bölme işlemi ile karşılaşılınca oluşur, TypeError
: beraber işleme giremeyecek nesneler aynı işlemde bulunduğu zaman oluşur (örneğin string
ile float
çarpması yapmaya kalkışılırsa).
Yukarıdaki örnekte olduğu gibi tüm hata tipleri için tek bir genel durum oluşturmak çok iyi bir fikir değildir. Bunun yerine kullanıcıya nasıl bir hata yaptığını açıklayan bir mesaj iletebiliriz. Bunu yapmak için programda karşılaşılan hata tipini tespit edip buna göre mesaj yazdırmalıyız. Bunu except
bloğunda hata çeşidini belirterek yapabiliriz.
import sys
try:
t = float(sys.argv[1])
except IndexError:
print "Komut satirindan bir arguman girilmeli.."
sys.exit(1)
except ValueError:
print "t=%s bir sayi degil.." % sys.argv[1]
sys.exit(1)
v0 = 2; g = 9.81
y = v0*t - 0.5*g*t**2
print y
Yukarıdaki programın çıktısı aşağıdaki gibi olacaktır.
Terminal > python except3.py
Komut satirindan bir arguman girilmeli..
Terminal > python except3.py 0.1sn
t=0.1sn bir sayi degil..
Terminal > python except3.py 0.1
0.15095
Programda bir hata ile karşılaştığımızda ya bir hata mesajı yazdırıp sys.exit()
ile programı sonlandırırız ya da bir exception üretiriz. İkinci işlem oldukça kolaydır ve raise E(mesaj)
komutuyla yapılır. Burada E
ile bir bilinen exception türü, mesaj ile de yazdırılacak mesajı belirtiriz.
import sys
try:
t = float(sys.argv[1])
except IndexError:
raise IndexError("Komut satirindan bir arguman girilmeli..")
except ValueError:
raise ValueError("t=%s bir sayi degil.." % sys.argv[1])
v0 = 2; g = 9.81
y = v0*t - 0.5*g*t**2
print y
Bu yöntemle Python'da anlamlı olan fakat yapılan işlem içinde istemedğimiz sonuç üretecek durumlar için de kontrol sağlanabilir. Örneğin yukarıdaki örnekte $t$ aralığı $[0, 2v_0/g]$ biçiminde olmalıdır, aksi halde konum fiziksel olarak anlamsız olan negatif değerler olarak hesaplanır. Bu aralık dışında değerleri girilince raise
ifadesi yardımıyla bir exception üretip programı durdurabiliriz.
import sys
try:
t = float(sys.argv[1])
except IndexError:
raise IndexError("Komut satirindan bir arguman girilmeli..")
except ValueError:
raise ValueError("t=%s bir sayi degil.." % sys.argv[1])
v0 = 2; g = 9.81
if not 0 <= t <= 2*v0/g:
raise ValueError("t=%g degeri [%g, %g] araliginda degil.." \
% (t, 0, 2*v0/g))
y = v0*t - 0.5*g*t**2
print y
Bu programın çıktısı aşağıdaki gibi olacaktır.
Terminal > python except5.py 0.1sn
Traceback (most recent call last):
File "except5.py", line 8, in
raise ValueError("t=%s bir sayi degil.." % sys.argv[1])
ValueError: t=0.1sn bir sayi degil..
Traceback (most recent call last):
File "except5.py", line 14, in
% (t, 0, 2*v0/g))
ValueError: t=1 degeri [0, 0.407747] araliginda degil..
Burada hata kontrolü uygun biçimde yapılmış oldu ama tek bir sıkıntı var, hata mesajları kullanıcı açısından biraz karmaşık görünüyor. Kullanıcı kaynak kodları ve teknik bilgileri görmeden sadece uygun bir hata mesaji gösterilerek bilgilendirilebilir. Bunu yapmak için sadece kullanıcı girişini okuyan ve hata kontrolü yapan bir fonksiyon tanımlarız, daha sonra bunu ana programda tekrar try-except
bloğundan geçiririz.
import sys
v0 = 2; g = 9.81
def veri_al():
try:
t = float(sys.argv[1])
except IndexError:
raise IndexError("Komut satirindan bir arguman girilmeli..")
except ValueError:
raise ValueError("t=%s bir sayi degil.." % sys.argv[1])
if not 0 <= t <= 2*v0/g:
raise ValueError("t=%g degeri [%g, %g] araliginda degil.." \
% (t, 0, 2*v0/g))
return t
try:
t = veri_al()
except Exception as E:
print E
sys.exit(1)
y = v0*t - 0.5*g*t**2
print y
Python'da hata (exception) kontrolünün önerilen yöntemi bu son yazdığımız programda yaptığımız gibidir. Programın çıktısı aşağıdaki gibi olacaktır.
Terminal > python except6.py 1
t=1 degeri [0, 0.407747] araliginda degil..
Terminal > python except6.py 1sn
t=1sn bir sayi degil..
Terminal > python except6.py
Komut satirindan bir arguman girilmeli..
Terminal > python except6.py 0.1
0.15095
3.1. Python Fonksiyonları
Python ve Bilimsel Hesaplama
3.3. Python'da Modüller