Kullanıcıyla İletişim: Veri Alış-Verişi¶
Bu bölümde de Python’daki önemli konulara değinmeye devam ediyoruz. Bu defaki konumuz “kullanıcıyla iletişim”.
Dikkat ettiyseniz, şimdiye dek sadece tek yönlü bir programlama faaliyeti içinde bulunduk. Yani yazdığımız kodlar kullanıcıyla herhangi bir etkileşim içermiyordu. Ama artık, Python’da bazı temel şeyleri öğrendiğimize göre, kullanıcıyla nasıl iletişim kurabileceğimizi de öğrenmemizin vakti geldi. Bu bölümde kullanıcılarımızla nasıl veri alış-verişinde bulunacağımızı göreceğiz.
Hatırlarsanız geçen bölümde şöyle bir örnek vermiştik:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
santigrat = 22
fahrenhayt = santigrat * (9.0/5.0) + 32
print ("%s santigrat derece %s fahrenhayta karşılık gelir."
%(santigrat, fahrenhayt))
Dikkat ederseniz burada santigrat değişkenini kendimiz kod içinde elle belirledik. Dolayısıyla formüle giren bütün sayılar zaten belli olduğu için bu kodların nasıl bir çıktı vereceğini de biliyoruz. Böyle bir kod yazımının ne kadar sıkıcı olduğu ortada... Bu santigrat değişkenini kendimiz elle yazmak yerine, kullanıcıya sorabilsek ve kullanıcının girdiği miktara göre hesaplama yapabilsek ne güzel olurdu, değil mi? Böylece her defasında farklı bir değer alıp bunu hesaplayabilen esnek bir programımız olurdu. İşte bu bölümde böyle bir programı nasıl yazabileceğimizi öğreneceğiz.
Python’da kullanıcıdan birtakım veriler alabilmek, yani kullanıcıyla iletişime geçebilmek için iki tane fonksiyondan faydalanılır: raw_input() ve input() (Bu “fonksiyon” kelimesine takılmayın. Birkaç bölüm sonra fonksiyonun ne demek olduğunu inceleyeceğiz.) Bu iki fonksiyon birbirlerinden bazı farklılıklar gösterir. Bunlardan öncelikle ilkine bakalım.
raw_input() fonksiyonu¶
raw_input() fonksiyonu kullanıcılarımızın klavye aracılığıyla girdiği verileri almamızı sağlar. İsterseniz bu fonksiyonu tarif etmeye çalışmak yerine hemen bununla ilgili bir örnek verelim. Öncelikle boş bir Kwrite (veya Gedit ya da IDLE) belgesi açalım. Her zaman yaptığımız gibi, ilk satırımızı ekleyelim belgeye:
#!/usr/bin/env python
Not
Bu satır sadece GNU/Linux kullanıcılarını ilgilendirir. Windows kullanıcıları bu satırı yazmasalar da olur. Bu satırın Windows’ta hiçbir etkisi yoktur.
Şimdi raw_input() fonksiyonuyla kullanıcıdan bazı bilgiler alacağız. Mesela kullanıcıya bir parola sorup kendisine teşekkür edelim...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
raw_input("Lütfen parolanızı girin:")
print "Teşekkürler!"
raw_input() fonksiyonunu nasıl kullandığımıza çok dikkat edin. Parantez içinde yazdığımız karakter dizisi, kullanıcıdan ne beklediğimizi göstermemizi sağlıyor. Buna göre biz bu kodlarla kullanıcıdan parolasını girmesini isteyeceğiz.
Şimdi bu belgeyi deneme.py ismiyle kaydediyoruz. Daha sonra bir konsol ekranı açıp, programımızın kayıtlı olduğu dizine geçerek şu komutla programımızı çalıştırıyoruz:
python deneme.py
Elbette siz isterseniz daha önce anlattığımız şekilde dosyaya çalıştırma yetkisi vererek ve gerekli düzenlemeleri yaparak programınızı doğrudan ismiyle de çağırabilirsiniz. Bu sizin tercihinize kalmış.
Program çalıştığında, kullanıcı “Lütfen parolanızı girin: ” cümlesini görecek ve böylece kendisinden ne beklendiğini anlayacak. Elbette raw_input() fonksiyonundaki parantezi boş da bırakabilirsiniz. Ancak çoğu zaman, parantez içine açıklayıcı bir şeyler yazmak isteyeceksiniz. Çünkü aksi halde programınız çalıştığında kullanıcınız ne yapması gerektiğini anlayamayacaktır.
Windows kullanıcıları esasında bu fonksiyonu önceki derslerimizden hatırlayacaktır. Bu fonksiyonu Windows’ta çift tıklayarak çalıştırmak istediğimiz programlarda MS-DOS ekranının program sonunda kapanmasını önlemek için kullanmıştık. O örnekte gösterdiğimiz programı şu şekilde yazarsak herhalde raw_input() fonksiyonunun oradaki görevi daha belirgin bir şekilde ortaya çıkacaktır:
# -*- coding: cp1254 -*-
a = "elma"
b = "armut"
c = "muz"
print "bir", a, "bir", b, "bir de", c, "almak istiyorum"
raw_input("Programdan çıkmak için ENTER tuşuna basın.")
Biz o dersteki örnekte parantez içini boş bırakmıştık...
Dilerseniz biraz önce yazdığımız parola soran programı biraz geliştirelim. Mesela programımız şu işlemleri yapsın:
- Program ilk çalıştırıldığında kullanıcıya parola sorsun,
- Kullanıcı parolasını girdikten sonra programımız kullanıcıya teşekkür etsin,
- Bir sonraki satırda kullanıcı tarafından girilen bu parola ekrana yazdırılsın,
- Kullanıcı daha sonraki satırda parolanın yanlış olduğu konusunda uyarılsın.
Şimdi kodlarımızı yazmaya başlayabiliriz. Öncelikle yazacağımız kodlardan bağımsız olarak girmemiz gereken bilgileri ekleyelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
Şimdi raw_input() fonksiyonuyla kullanıcıya parolasını soracağız. Ama isterseniz bu raw_input() fonksiyonunu bir değişkene atayalım:
parola = raw_input("Parolanızı girin:")
Şimdi kullanıcıya teşekkür ediyoruz:
print "Teşekkürler!"
Kullanıcı tarafından girilen parolayı ekrana yazdırmak için şu satırı ekliyoruz:
print parola
Biraz önce raw_input() fonksiyonunu neden bir değişkene atadığımızı anladınız sanırım. Bu sayede doğrudan parola değişkenini çağırarak kullanıcının yazdığı parolayı ekrana dökebiliyoruz.
Şimdi de kullanıcıya parolasının yanlış olduğunu bildireceğiz:
print "Ne yazık ki doğru parola bu değil"
Programımızın son hali şöyle olacak:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
parola = raw_input("Parolanızı girin:")
print "Teşekkürler!"
print parola
print "Ne yazık ki doğru parola bu değil."
İsterseniz son satırda şu değişikliği yapabiliriz:
print "Ne yazık ki doğru parola", parola, "değil."
Böylelikle, parola değişkenini, yani kullanıcının yazdığı parolayı cümlemizin içine (ya da Pythonca ifade etmek gerekirse: “karakter dizisi içine”) eklemiş olduk.
Bu parola değişkenini karakter dizisi içine eklemenin başka bir yolu da kodu şu şekilde yazmaktır:
print "Ne yazık ki doğru parola %s değil" %(parola)
Bu sayede kullanıcının girdiği parolayı istediğiniz gibi biçimlendirebilirsiniz. Mesela kullanıcıdan gelen parolayı tırnak içine alarak cümle içinde daha belirgin durmasını sağlayabilirsiniz:
print "Ne yazık ki doğru parola '%s' değil" %(parola)
Şimdi raw_input() fonksiyonuna bir ara verip, kullanıcıdan bilgi almak için kullanabileceğimiz ikinci fonksiyondan biraz bahsedelim. Az sonra raw_input() fonksiyonuna geri döneceğiz.
input() fonksiyonu¶
Tıpkı raw_input() fonksiyonunda olduğu gibi, input() fonksiyonuyla da kullanıcılardan bazı bilgileri alabiliyoruz. Şu basit örneğe bir bakalım:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
a = input("Lütfen bir sayı girin:")
b = input("Lütfen başka bir sayı daha girin:")
print a + b
Kullanım açısından, görüldüğü gibi, raw_input() ve input() fonksiyonları birbirlerine çok benzer. Ama bunların arasında çok önemli bir fark vardır. Hemen yukarıda verilen kodları bir de raw_input() fonksiyonuyla yazmayı denersek bu fark çok açık bir şekilde ortaya çıkacaktır:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
a = raw_input("Lütfen bir sayı girin:")
b = raw_input("Lütfen başka bir sayı daha girin:")
print a + b
Bu kodları yazarken input() fonksiyonunu kullanırsak, kullanıcı tarafından girilen sayılar birbirleriyle toplanacaktır. Diyelim ki ilk girilen sayı 25, ikinci sayı ise 40 olsun. Programın sonunda elde edeceğimiz sayı 65 olacaktır.
Ancak bu kodları yazarken eğer raw_input() fonksiyonunu kullanırsak, girilen sayılar birbirleriyle toplanmayacak, sadece yan yana yazılacaklardır. Yani elde edeceğimiz şey 2540 olacaktır.
Hatırlarsanız buna benzer bir şeyle “sayılar” konusunu işlerken de karşılaşmıştık. O zaman şu örnekleri vermiştik:
>>> print 25 + 50
75
>>> print "25" + "50"
2550
İşte raw_input() ile input() arasındaki fark, yukarıdaki iki örnek arasındaki farka benzer. Yukarıdaki örneklerde, Python’ın sayılara ve karakter dizilerine nasıl davrandığını görüyoruz. Eğer Python iki adet sayıyla karşılaşırsa bu sayıları birbiriyle topluyor. Ama eğer iki adet karakter dizisiyle karşılaşırsa, bu karakter dizilerini yanyana yazmakla yetiniyor...
Bütün bu açıklamalardan anlıyoruz ki raw_input() fonksiyonu kullanıcının girdiği verileri karakter dizisine dönüştürüyor. Bu durumu daha net görebilmek için dilerseniz şöyle bir örnek verelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
sayi = raw_input("Bir sayı girin. Ben size o \
sayının karesini söyleyeyim:\n")
print "girdiğiniz sayı\t\t: %s" %(sayi)
print "girdiğiniz sayının karesi: %s" % (sayi * sayi)
Bu kodları çalıştırdığınızda sayıyı girip ENTER tuşuna bastıktan sonra şöyle bir hata mesajı alacaksınız:
File "deneme.py", line 8, in <module>
print "girdiğiniz sayının karesi: %s" % (sayi * sayi)
TypeError: can't multiply sequence by non-int of type 'str'
Bu durum, raw_input() fonksiyonunun kullanıcı verilerini karakter dizisi olarak almasından kaynaklanıyor. Karakter dizileri ile aritmetik işlem yapılamayacağı için de hata vermekten başka çaresi kalmıyor. Burada tam olarak ne döndüğünü anlayabilmek için etkileşimli kabukta verdiğimiz şu örneklere bakalabilirsiniz:
>>> a = "12"
>>> b = "12"
>>> print a * b
TypeError: can't multiply sequence by non-int of type 'str'
Gördüğünüz gibi biraz öncekiyle aynı hatayı aldık. İki karakter dizisini birbiriyle çarpamaz, bölemez ve bu karakter dizilerini birbirinden çıkaramazsınız. Çünkü aritmetik işlemler ancak sayılar arasında olur. Karakter dizileri ile aritmetik işlem yapılmaz... Yukarıdaki örneklerin düzgün çıktı verebilmesi için o örnekleri şöyle yazmamız gerekir:
>>> a = 12
>>> b = 12
>>> print a * b
144
Dolayısıyla, yukarıda hata veren kodlarımızın da düzgün çalışabilmesi için o kodları şöyle yazmamız gerek:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
sayi = input("Bir sayı girin. Ben size o \
sayının karesini söyleyeyim:\n")
print "girdiğiniz sayı\t\t: %s" %(sayi)
print "girdiğiniz sayının karesi: %s" % (sayi * sayi)
raw_input() fonksiyonundan farklı olarak input() fonksiyonu kullanıcıdan gelen verileri olduğu gibi alır. Yani bu verileri karakter dizisine dönüştürmez. Bu yüzden, eğer kullanıcı bir sayı girmişse, input() fonksiyonu bu sayıyı olduğu gibi alacağı için, bizim bu sayıyla aritmetik işlem yapmamıza müsaade eder. Bu durumu daha iyi anlayabilmek için mesela aşağıda raw_input() fonksiyonuyla yazdığımız kodları siz bir de input() fonksiyonuyla yazmayı deneyin:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
a = raw_input("isminiz: ")
b = raw_input("soyisminiz: ")
print a, b
Eğer bu kodları input() fonksiyonuyla yazmayı denediyseniz, Python’ın ilk veri girişinden sonra şöyle bir hata verdiğini görmüşsünüzdür:
SyntaxError: invalid syntax
Etkileşimli kabukta şu komutu verdiğinizde de aynı hatayı aldığınızı göreceksiniz:
>>> Ahmet
SyntaxError: invalid syntax
Burada hata almamak için şöyle yapmak gerek:
>>> "Ahmet"
'Ahmet'
Dolayısıyla Python’ın input() fonksiyonuyla bu hatayı vermemesi için de tek yol, kullanıcının ismini ve soyismini tırnak içinde yazması olacaktır. Ama tabii ki normal şartlarda kimseden ismini ve soyismini tırnak içinde yazmasını bekleyemezsiniz.
Bütün bunlardan şunu anlıyoruz:
input() fonksiyonu, kullanıcının geçerli bir Python komutu girmesini bekler. Yani eğer kullanıcının girdiği şey Python’ın etkileşimli kabuğunda hata verecek bir ifade ise, input()‘lu kodunuz da hata verecektir.
Dolayısıyla eğer biz programımız aracılığıyla kullanıcılardan bazı sayılar isteyeceksek ve eğer biz bu sayıları işleme sokacaksak (çıkarma, toplama, bölme gibi...) input() fonksiyonunu tercih edebiliriz. Ama eğer biz kullanıcılardan sayı değil de karakter dizisi girmesini istiyorsak raw_input() fonksiyonunu kullanacağız.
Şimdi dilerseniz bu bölümün en başında verdiğimiz fahrenhayta dönüştürme programını, yeni öğrendiğimiz bilgiler yardımıyla biraz geliştirelim:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
santigrat = input("Santigrat cinsinden bir değer girin: ")
fahrenhayt = santigrat * (9.0/5.0) + 32
print ("%s santigrat derece %s fahrenhayta karşılık gelir."
%(santigrat, fahrenhayt))
Böylece elimizde gayet şık bir derece dönüştürme programı olmuş oldu.. Günün birinde santigrat dereceleri fayhrenhayta dönüştürmeniz gerekirse yukarıdaki programı kullanabilirsiniz...
Güvenlik Açısından input() ve raw_input()¶
Yukarıda da bahsettiğimiz gibi, Python’da kullanıcıdan veri alabilmek için input() ve raw_input() adlı iki farklı fonksiyondan faydalanıyoruz. Bu iki fonksiyonun kendilerine has görevleri ve kullanım alanları vardır. Ancak eğer yazdığınız kodlarda güvenliği de ön planda tutmak isterseniz input() fonksiyonundan kaçınmayı tercih edebilirsiniz. Çünkü input() fonksiyonu kullanıcıdan gelen bilgiyi bir komut olarak algılar. Peki bu ne anlama geliyor?
Şimdi şöyle bir kod yazdığımızı düşünün:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
sayi = input("bir sayı girin: ")
print sayi
Bu kodlarımızı çalıştırdığımızda “bir sayı girin: ” sorusuyla karşılaşacağız. Şimdi bu soruya cevap olarak şunları yazalım:
2 + 2
Bunu yazıp ENTER tuşuna bastığımızda 4 çıktısını elde ediyoruz. Bu demek oluyor ki, input() fonksiyonu kullanıcıdan gelen bilgiyi bir komut olarak yorumladığı için, bu fonksiyon yardımıyla kullanıcılarımız Python kodlarını çalıştırabiliyor. Ne güzel, değil mi? Hiç de değil! Başta çok hoş bir özellik gibi görünse de bu, aslında beraberinde bazı güvenlik risklerini de getirir. Şimdi yukarıdaki programı tekrar çalıştırın ve soruya şu cevabı yazın:
eval("__import__('os').system('dir')")
ENTER tuşuna bastığınızda, o anda içinde bulunduğunuz dizin altındaki dosyaların ekranda listelendiğini göreceksiniz. Yukarıdaki satırda geçen komutları henüz öğrenmedik. Ama yukarıdaki satır yardımıyla sistem komutlarını çalıştırabildiğimizi görüyorsunuz. Burada gördüğümüz dir bir sistem komutudur. Bu komutun görevi bir dizin altındaki dosyaları listelemek. Mesela GNU/Linux’ta dosya silmemizi sağlayan komut rm, Windows’ta ise del‘dir. Dolayısıyla yukarıdaki komutu şu şekilde yazdığımızda neler olabileceğini bir düşünün:
eval("__import__('os').system('rm bir_dosya')")
veya:
eval("__import__('os').system('del bir_dosya')")
Hatta bu satır, şimdi burada göstermek istemediğimiz, çok daha yıkıcı sonuçlar doğurabilecek sistem komutlarının çalıştırılabilmesini sağlar (bütün sabit diski silmek gibi...). Dolayısıyla eğer özellikle sunucu üzerinden çalışacak kodlar yazıyorsanız input() fonksiyonunu kullanırken dikkatli olmalısınız.
input() fonksiyonunun yukarıdaki risklerinden ötürü Python programcıları genellikle bu fonksiyonu kullanmamayı tercih eder. Bunun yerine her zaman raw_input() fonksiyonu kullanılır. Zaten raw_input() fonksiyonu kullanıcıyla veri alış-verişine ilişkin bütün ihtiyaçlarımızı karşılayacak özelliktedir. Ancak biz henüz raw_input() fonksiyonunu tam kapasite kullanacak kadar bilgi sahibi değiliz. Birkaç bölüm sonra eksik bilgilerimizi de tamamladıktan sonra input() fonksiyonuna hiç ihtiyacınız olmadığını göreceksiniz. Ama biz şimdilik input() fonksiyonundan yararlanmaya devam edeceğiz. Çünkü düşmanımızı tanımalıyız ki düşmanımızdan korunabilelim...
Bölüm Soruları¶
1. Ana görevi doğum yılı sorup yaş hesaplamak olan bir program yazın. Yazdığınız program kullanıcıya ismiyle hitap edip, ona yaşını söyleyebilmeli.
2. Türk Lirası’nı günlük kura göre Dolar, Euro ve Sterlin’e çeviren bir program yazın. Program kullanıcıdan TL miktar alıp bu miktarı kullanıcıya Dolar, Euro ve Sterlin olarak geri bildirebilmeli.
3. 2009 yılı Nisan ayının ilk gününe ait Dolar kuru ile 2010 yılı Nisan ayının ilk gününe ait Dolar kurunu karşılaştırın ve bir yıllık değişimin yüzdesini hesaplayın.
4. Bir önceki soruda yazdığınız programı, gerekli değerleri kullanıcıdan alarak tekrar yazın.
5. raw_input() ile input() fonksiyonlarını birbiriyle karşılaştırın. input() fonksiyonunu kullanarak bir sisteme ne tür zararlar verebileceğinizi ve bu zararları önlemek için teorik olarak neler yapabileceğinizi düşünün.
6. Aşağıdaki iki kodu karşılaştırın ve birinci kod hatasız çalışırken, ikinci kodun hata vermesinin sebebini açıklayın.
>>> print "Hayır! " * 5
>>> print "Hayır! " * "Hayır! "
blog comments powered by Disqus