12eval exec format.fw min

Python Ders 12 | eval() exec() ve format() Fonksiyonları

eval() ve exec()

Bir önceki bölümün son örnek programında eval() adlı bir fonksiyonla karşılaşmıştık.eval() fonksiyonunu anlatmaya başlamadan önce şu uyarıyı yapalım:eval() ŞEYTANİ GÜÇLERİ OLAN BİR FONKSİYONDUR!

Bunun neden böyle olduğunu hem biz anlatacağız, hem de zaten bu fonksiyonu tanıdıkça neden eval()’e karşı dikkatli olmanız gerektiğini kendiniz de anlayacaksınız.

Dilerseniz işe basit bir eval() örneği vererek başlayalım:

print("""
Basit bir hesap makinesi uygulaması.

İşleçler:

    +   toplama
    -   çıkarma
    *   çarpma
    /   bölme

Yapmak istediğiniz işlemi yazıp ENTER
tuşuna basın. (Örneğin 23 ve 46 sayılarını
çarpmak için 23 * 46 yazdıktan sonra
ENTER tuşuna basın.)
""")

veri = input("İşleminiz: ")
hesap = eval(veri)

print(hesap)

İngilizcede evaluate diye bir kelime bulunur. eval() fonksiyonundaki eval kelimesi bu evaluate kelimesinin kısaltmasıdır.

Bu fonksiyonun görevi, kendisine verilen karakter dizilerini değerlendirmeye tabi tutmak ya da işlemektir. Peki bu tam olarak ne anlama geliyor?

Kullanıcıdan gelen veriyi eval() fonksiyonu yardımıyla değerlendirmeye tabi tutuyoruz. Yani kullanıcının girdiği komutları işleme sokuyoruz.

Örneğin, kullanıcı 46 / 2 gibi bir veri girdiyse, biz eval() fonksiyonu yardımıyla bu 46 / 2 komutunu işletiyoruz. Bu işlemin sonucunu da hesap adlı başka bir değişken içinde depoluyoruz.

Eğer burada eval() fonksiyonunu kullanmazsak, programımız, kullanıcının girdiği 45 * 76 komutunu hiçbir işleme sokmadan dümdüz ekrana basacaktır. Yani:

print("""
Basit bir hesap makinesi uygulaması.

İşleçler:

    +   toplama
    -   çıkarma
    *   çarpma
    /   bölme

Yapmak istediğiniz işlemi yazıp ENTER
tuşuna basın. (Örneğin 23 ve 46 sayılarını
çarpmak için 23 * 46 yazdıktan sonra
ENTER tuşuna basın.)
""")

veri = input("İşleminiz: ")

print(veri)

eval() fonksiyonunun, yukarıda anlattığımız özelliklerini okuduktan sonra, ‘Ne güzel bir fonksiyon! Her işimi görür bu!’ dediğinizi duyar gibiyim. Ama aslında durum hiç de öyle değil. Neden mi?

print("""
Basit bir hesap makinesi uygulaması.

İşleçler:

    +   toplama
    -   çıkarma
    *   çarpma
    /   bölme

Yapmak istediğiniz işlemi yazıp ENTER
tuşuna basın. (Örneğin 23 ve 46 sayılarını
çarpmak için 23 * 46 yazdıktan sonra
ENTER tuşuna basın.)
""")

veri = input("İşleminiz: ")
hesap = eval(veri)

print(hesap)

Şimdi yukarıdaki programı tekrar çalıştırın ve “İşleminiz: “ ifadesinden sonra şu cevabı verin:

print("Merhaba Python!")
Bu komut şöyle bir çıktı vermiş olmalı:
Merhaba Python!
None

Buradaki None değerini görmezden gelin. Bunu fonksiyonlar konusunu anlatırken inceleyeceğiz.

Gördüğünüz gibi, yazdığımız program, kullanıcının girdiği Python komutunun işletilmesine sebep oldu. Bu noktada, ‘Eee, ne olmuş!’ demiş olabilirsiniz.

Gelin bir de şuna bakalım. Şimdi programı tekrar çalıştırıp şu cevabı verin:

open("deneme.txt", "w")

Bu cevap, bilgisayarınızda deneme.txt adlı bir dosya oluşturulmasına sebep oldu. Belki farkındasınız, belki farkında değilsiniz, ama aslında şu anda kendi yazdığınız program sizin kontrolünüzden tamamen çıktı.

Siz aslında bir hesap makinesi programı yazmıştınız. Ama eval() fonksiyonu nedeniyle kullanıcıya rastgele Python komutlarını çalıştırma imkanı verdiğiniz için programınız sadece aritmetik işlemleri hesaplamak için kullanılmayabilir.

Böyle bir durumda kötü niyetli (ve bilgili) bir kullanıcı size çok büyük zarar verebilir.

Ayrıca eval() fonksiyonu kullanılacağı zaman, kullanıcıdan gelen veri bu fonksiyona parametre olarak verilmeden önce sıkı bir kontrolden geçirilir.

Örneğin, kullanıcınızın, izin verilen değerler harici bir değer girmesini engelleyebilirsiniz. Bu durumu somutlaştırmak için şöyle bir diyagram çizebiliriz:

_images/eval_yanlis.png

Yukarıdaki diyagram eval() fonksiyonunun yanlış uygulanış biçimini gösteriyor. Gördüğünüz gibi, veri doğrudan eval() fonksiyonuna gidiyor ve çıktı olarak veriliyor.

Aşağıdaki diyagram ise eval() fonksiyonunun doğru uygulanış biçimini gösteriyor:

_images/eval_dogru.png

Burada ise, veri eval() fonksiyonuna ulaşmadan önce kontrolden geçiriliyor.

Eğer veri ancak kontrol aşamasından geçerse eval() fonksiyona ulaşabilecek ve oradan da çıktı olarak verilebilecektir. Böylece kullanıcıdan gelen komutları süzme imkanına sahip oluyoruz.

Python’da eval() fonksiyonuna çok benzeyen exec() adlı başka bir fonksiyon daha bulunur.

Örneğin eval() fonksiyonu bir karakter dizisi içindeki değişken tanımlama işlemini yerine getiremez. Yani eval() ile şöyle bir şey yapamazsınız:

>>> eval("a = 45")
Ama exec() ile böyle bir işlem yapabilirsiniz:
>>> exec("a = 45")

Böylece a adlı bir değişken tanımlamış olduk. Kontrol edelim:

>>> print(a)

45

eval() ve exec() fonksiyonları özellikle kullanıcıdan alınan verilerle doğrudan işlem yapmak gereken durumlarda işinize yarar.

Aynı şekilde mesela insanlara Python programlama dilini öğreten bir program yazıyorsanız exec() fonksiyonunu şöyle kullanabilirsiniz:

d1 = """

Python'da ekrana çıktı verebilmek için print() adlı bir
fonksiyondan yararlanıyoruz. Bu fonksiyonu şöyle kullanabilirsiniz:

>>> print("Merhaba Dünya")

Şimdi de aynı kodu siz yazın!

>>> """

girdi = input(d1)

exec(girdi)

d2 = """

Gördüğünüz gibi print() fonksiyonu, kendisine
parametre olarak verilen değerleri ekrana basıyor.

Böylece ilk dersimizi tamamlamış olduk. Şimdi bir
sonraki dersimize geçebiliriz."""

print(d2)

eval() fonksiyonunu anlatırken güvenlik ile ilgili olarak söylediğimiz her şey exec() fonksiyonu için de geçerlidir.

Dolayısıyla bu iki fonksiyonu çok dikkatli bir şekilde kullanmanız ve bu fonksiyonların doğurduğu güvenlik açığının bilincinde olmanız gerekiyor.

format() Metodu

İnternette dolaşırken mutlaka şuna benzer bir sayfayla karşılaşmış olmalısınız:

_images/unknown_url.png

Böyle bir internet adresi olmadığı için, kullandığımız internet tarayıcısı bize şöyle bir mesaj vermiş:

Hata! Google Chrome fdkgd.com sitesini bulamadı

Şimdi de dadasdaf.com adresini arayalım…

Yine böyle bir adres olmadığı için, bu defa tarayıcımız bize şöyle bir uyarı gösterecek:

Hata! Google Chrome dadasdaf.com sitesini bulamadı

Gördüğünüz gibi, hata mesajlarında değişen tek yer, aradığımız sitenin adresi. Yani internet tarayıcımız bu hata için şöyle bir taslağa sahip:

Hata! Google Chrome ... sitesini bulamadı

Burada … ile gösterdiğimiz yere, bulunamayan URL yerleştiriliyor. Peki böyle bir şeyi Python programlama dili ile nasıl yapabiliriz?

Çok basit:

#Öncelikle kullanıcıdan bir internet adresi girmesini istiyoruz
url = input("Lütfen ulaşmak istediğiniz sitenin adresini yazın: ")

#Şimdi de bu adresin bulunamadığı konusunda kullanıcıyı bilgilendiriyoruz
print("Hata! Google Chrome", url, "sitesini bulamadı")

Gördüğünüz gibi, şimdiye kadar öğrendiğimiz bilgileri kullanarak böyle bir programı rahatlıkla yazabiliyoruz.

İşte bu tür ‘karakter dizisi biçimlendirme’ işlemleri için Python bize çok faydalı bir araç sunuyor. Bu aracın adı format().

Bu aracı şöyle kullanıyoruz:

#Öncelikle kullanıcıdan bir internet adresi girmesini istiyoruz
url = input("Lütfen ulaşmak istediğiniz sitenin adresini yazın: ")

#Şimdi de bu adresin bulunamadığı konusunda kullanıcıyı bilgilendiriyoruz
print("Hata! Google Chrome {} sitesini bulamadı".format(url))

Bir de bulunamayan internet adresini tırnak içine alalım:

print("Hata! Google Chrome '{}' sitesini bulamadı".format(url))

Peki format() nasıl çalışıyor?

Bunu anlamak için şu basit örneklere bir bakalım:

>>> print("{} ve {} iyi bir ikilidir".format("Python", "Django"))

'Python ve Django iyi bir ikilidir'

>>> print("{} {}'yi seviyor!".format("Ali", "Ayşe"))

'Ali Ayşe'yi seviyor!'

>>> print("{} {} yaşında bir {}dur".format("Ahmet", "18", "futbolcu"))

'Ahmet 18 yaşında bir futbolcudur'
Elbette bu örnekleri şöyle de yazabilirdik:
>>> metin = "{} ve {} iyi bir ikilidir"
>>> metin.format("Python", "Django")

'Python ve Django iyi bir ikilidir'

>>> metin = "{} {}'yi seviyor!"
>>> metin.format("Ali", "Ayşe")

'Ali Ayşe'yi seviyor!'

>>> metin = "{} {} yaşında bir {}dur"
>>> metin.format("Ahmet", "18", "futbolcu")

'Ahmet 18 yaşında bir futbolcudur'

Burada taslak metni doğrudan format() metoduna parametre olarak vermeden önce bir değişkene atadık. Böylece bu metni daha kolay bir şekilde kullanabildik.

Başka bir örnek daha verelim.

Varsayalım ki kullanıcıdan aldığı bilgiler doğrultusunda, özel bir konu üzerine dilekçe oluşturan bir program yazmak istiyorsunuz.

Dilekçe taslağımız şu şekilde olsun:

                                                        tarih:

T.C.
... ÜNİVERSİTESİ
... Fakültesi Dekanlığına


Fakülteniz ..........Bölümü ......... numaralı öğrencisiyim. Ekte sunduğum
belgede belirtilen mazeretim gereğince ....... Eğitim-Öğretim Yılı  .........
yarıyılında öğrenime ara izni (kayıt dondurma) istiyorum.

    Bilgilerinizi ve gereğini arz ederim.

    İmza

Ad-Soyadı       :
T.C. Kimlik No. :
Adres           :
Tel.            :
Ekler           :


Amacınız bu dilekçedeki boşluklara gelmesi gereken bilgileri kullanıcıdan alıp, eksiksiz bir dilekçe ortaya çıkarmak.

Kullanıcıdan bilgi alma kısmı kolay. input() fonksiyonunu kullanarak gerekli bilgileri kullanıcıdan alabileceğimizi biliyorsunuz:

tarih           = input("tarih: ")
üniversite      = input("üniversite adı: ")
fakülte         = input("fakülte adı: ")
bölüm           = input("bölüm adı: ")
öğrenci_no      = input("öğrenci no. :")
öğretim_yılı    = input("öğretim yılı: ")
yarıyıl         = input("yarıyıl: ")
ad              = input("öğrencinin adı: ")
soyad           = input("öğrencinin soyadı: ")
tc_kimlik_no    = input("TC Kimlik no. :")
adres           = input("adres: ")
tel             = input("telefon: ")
ekler           = input("ekler: ")

Bilgileri kullanıcıdan aldık. Peki ama bu bilgileri dilekçe taslağı içindeki boşluklara nasıl yerleştireceğiz?

Şimdi çok dikkatlice inceleyin şu kodları:

dilekçe = """
                                                    tarih: {}


T.C.
{} ÜNİVERSİTESİ
{} Fakültesi Dekanlığına


Fakülteniz {} Bölümü {} numaralı öğrencisiyim. Ekte sunduğum belgede
belirtilen mazeretim gereğince {} Eğitim-Öğretim Yılı  {}.
yarıyılında öğrenime ara izni (kayıt dondurma) istiyorum.

    Bilgilerinizi ve gereğini arz ederim.

        İmza

Ad              : {}
Soyad           : {}
T.C. Kimlik No. : {}
Adres           : {}
Tel.            : {}
Ekler           : {}
"""


tarih           = input("tarih: ")
üniversite      = input("üniversite adı: ")
fakülte         = input("fakülte adı: ")
bölüm           = input("bölüm adı: ")
öğrenci_no      = input("öğrenci no. :")
öğretim_yılı    = input("öğretim yılı: ")
yarıyıl         = input("yarıyıl: ")
ad              = input("öğrencinin adı: ")
soyad           = input("öğrencinin soyadı: ")
tc_kimlik_no    = input("TC Kimlik no. :")
adres           = input("adres: ")
tel             = input("telefon: ")
ekler           = input("ekler: ")

print(dilekçe.format(tarih, üniversite, fakülte, bölüm,
                     öğrenci_no, öğretim_yılı, yarıyıl,
                     ad, soyad, tc_kimlik_no,
                     adres, tel, ekler))


Bu kodlara (ve bundan önceki örneklere) bakarak birkaç tespitte bulunalım:

  1. Taslak metinde kullanıcıdan alınacak bilgilerin olduğu yerlere birer {} işareti yerleştirdik.
  2. Taslaktaki eksiklikleri tamamlayacak verileri input() fonksiyonu yardımıyla kullanıcıdan tek tek aldık.
  3. Son olarak, print() fonksiyonu yardımıyla metni tam bir şekilde ekrana çıktı olarak verdik.

Şimdi son tespitimizi biraz açıklayalım. Gördüğünüz gibi, print() fonksiyonu içinde dilekçe.format() gibi bir yapı var. Burada dilekçe değişkenine nokta işareti ile bağlanmış format() adlı, fonksiyon benzeri bir araç görüyoruz.

Bu araca teknik dilde ‘metot’ adı verilir. format() metodunun parantezleri içinde ise, kullanıcıdan alıp birer değişkene atadığımız veriler yer alıyor.

Dilerseniz yukarıda olan biteni daha net anlayabilmek için bu konunun başına verdiğimiz örneklere geri dönelim.

İlk olarak şöyle bir örnek vermiştik:
#Öncelikle kullanıcıdan bir internet adresi girmesini istiyoruz
url = input("Lütfen ulaşmak istediğiniz sitenin adresini yazın: ")

#Şimdi de bu adresin bulunamadığı konusunda kullanıcıyı bilgilendiriyoruz
print("Hata! Google Chrome {} sitesini bulamadı".format(url))

Burada kullanıcının gireceği internet adresinin yerini tutması için {} işaretlerinden yararlanarak şöyle bir karakter dizisi oluşturduk:

print("Hata! Google Chrome {} sitesini bulamadı".format(url))

Elbette eğer istersek yukarıdaki örneği şöyle de yazabilirdik:

url = input("Lütfen ulaşmak istediğiniz sitenin adresini yazın: ")

#Kullanıcıya gösterilecek hata için bir taslak metin oluşturuyoruz
hata_taslağı = "Hata! Google Chrome {} sitesini bulamadı"

print(hata_taslağı.format(url))

Burada hata metnini içeren karakter dizisini doğrudan format() metoduna bağlamak yerine, bunu bir değişkene atayıp, format() metodunu bu değişkene bağladık.

Bunun dışında şu örnekleri de vermiştik:

>>> metin = "{} ve {} iyi bir ikilidir"
>>> metin.format("Python", "Django")

'Python ve Django iyi bir ikilidir

>>> metin = "{} {}'yi seviyor!"
>>> metin.format("Ali", "Ayşe")

'Ali Ayşe'yi seviyor!'

>>> metin = "{} {} yaşında bir {}dur"
>>> metin.format("Ahmet", "18", "futbolcu")

'Ahmet 18 yaşında bir futbolcudur'

Burada da, gördüğüz gibi, öncelikle bir karakter dizisi tanımlıyoruz. Bu karakter dizisi içindeki değişken değerleri ise {} işaretleri ile gösteriyoruz. Daha sonra format() metodunu alıp bu karakter dizisine bağlıyoruz.

Karakter dizisi içindeki {} işaretleri ile gösterdiğimiz yerlere gelecek değerleri de format() metodunun parantezleri içinde gösteriyoruz. Yalnız burada şuna dikkat etmemiz lazım:

Karakter dizisi içinde kaç tane {} işareti varsa, format() metodunun parantezleri içinde de o sayıda değer olması gerekiyor.

Bu eğitim seti Kaynak tarafından oluşturulmuştur.

İletişim: admin@herseymi.com
Yazı oluşturuldu 96

Bir Yorum Yazın

Benzer yazılar

Aramak istediğinizi üstte yazmaya başlayın ve aramak için enter tuşuna basın. İptal için ESC tuşuna basın.

Üste dön