Python - eval() Fonksiyonundan Korkmalı Mıyım?

Merhaba kodlab’ın python ders kitabında tkinter ünitesinde bir hesap makinesi kodlarken eval fonksiyonunu kullanmadan önce bunun tehlikeli bir fonksiyon olduğunu söylüyor. Neden tehlikeli olduğuna dair bir açıklama yapmıyor.

Tehlikeliden kastı nedir? Eval fonksiyonu içerisine gönderilen işlemi yapıp çıktı veriyor öyle değil mi? Bahsedilen ne olabilir?

Diyelim ki böyle bir hesap makinesi kodu olsun;

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)

Burada girilen değerleri kısıtlamazsak çok büyük bir açık olur ve kullanıcı eval fonk kullanarak istediğini yapabilir.
Örnek olarak dosya oluşturabilir veya mevcut dosyaları silerek sisteme zarar verebilir.

Mesela aşağıdaki gibi bir kısıtlama koyabilirsin.
Böylelikle başka bir işlemin yapılmasını engellersiniz.

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.)
""")
karset = "1234567890*/+-,. "
veri = input("İşleminiz: ")

for i in veri:
    if not i in karset:
        print("Neyin peşindesiniz...:(")
        quit()

hesap = eval(veri)
print(hesap)
2 Beğeni

Duzgun kullanildiginda cok faydali bir fonksiyon aslinda

1 Beğeni

Duzgun kullanilmadiginda Kullanici eval fonksiyonu icine sizin isteminiz disindaki python komutlarini calistira bilir ve bu cok tehlikeli ola bilir.internette arastirmanizi tavsiye ederim.

1 Beğeni

demek istediklerinizi anladım. cevaplarınız için teşekkür ederim

1 Beğeni

peki execin evaldan farkı ne ozaman?

Bildiğim farkları şunlar:

  1. eval ile değişken tanımlayamazken, exec ile tanımlayabilirsiniz.
eval("x = 1")  # hata yükseltir.
exec("x = 1")  # hata yükseltmez.
  1. eval, tek bir satırlık ifadeyi çalıştırırken; exec, kod bloklarını çalıştırır.
ifade = """for i in range(10):
    print(i)"""

eval(ifade)  # hata yükseltir.
exec(ifade)  # hata yükseltmez.
  1. eval, değer döndürürken; exec, değer döndürmez.
ifade = "1 + 2"

print(eval(ifade))  # 3 değerini döndürür.
print(exec(ifade))  # Değer döndürmez bu yüzden ekrana None yazılır.
2 Beğeni

Satır sayısının önemi yok, buradaki eval_input gramerine uygun herhangi bir kodu çalıştırabilir.

Satır sayısının birden fazla olduğu bir eval örneği paylaşabilir misiniz? Bildiğim kadarıyla eval birden fazla satırı olan if, while, def gibi deyimleri ve birden fazla satırı çalıştıramıyor, bunun yerine tek satırlık, ifade dediğimiz, değer döndüren şeyi çalıştırıyor.

Mesela:

>>> s = """(1,
2)"""
>>> eval(s)
(1, 2)

Tek satırlık kısmı dışında doğru, bu ifadelerin Python sözdizimindeki tanımını da yukarıdaki linkte verdim.

birden fazla satırlı olduğu doğru ama tek bir ifadenin birden fazla satırlısı değil mi bu? sonuçta satır birden fazla da olsa işlem tek. bence @dildeolupbiten bahsettiği durum satır sayısının sadece miktar olarak değil işlem olarak da fazlalığı.

Birden fazla işlem de yapabiliriz, hem de tek satırda:

>>> eval("print('merhaba') or print('dünya')")
merhaba
dünya
>>> 

Gerçi buradaki "işlem"i tam olarak hangi anlamda kullanıyorsunuz bilmiyorum.

“Satır sayısının işlem olarak fazlağı” ne oluyor anlamadım. @dildeolupbiten’in ne demek istediğini ben anladım zaten, sadece satır sayısının bu konuda bir sınırlama olmadığını söyledim. eval fonksiyonu birden fazla yeni satır karakteri içeren kodları çalıştırabilir. eval fonksiyonunun hangi kodları çalıştırabileceği verdiğim linkteki gramer ile kesin olarak belirlenmiş.

while True:
    
    sayi = int(input("sayi giriniz >> "))
    
    if sayi == 1:
        print("sayi doğru")
        break
    else:

        print("hatalı değer")

eval fonksiyonu şimdi bu üstte yazanı çalıştıracak mı?

Çok istiyorsak çalıştırır:

code = """
while True:
    
    sayi = int(input("sayi giriniz >> "))
    
    if sayi == 1:
        print("sayi doğru")
        break
    else:

        print("hatalı değer")
"""

code = compile(code, "", "exec")

eval(code)

eval fonksiyonunun zaten bytecode çalıştırma ile alakalı bir sınırlaması yok, sadece verdiğimiz parametre str ise belli bir sözdizimine uymalı.

1 Beğeni

@EkremDincel

Benim bahsettiğim ile sizin bahsettiğiniz arasında fark var. İki satırlık işlem olarak ben şundan bahsediyorum:

ifade = 'print("hello"); print("world")'

eval(ifade)

Zaten print("hello") or print("world") tek satırlık bir işlem. Benim bahsettiğim şey bu değil.

Şundan da bahsetmiyorum:

ifade = "2 + \
3 + \
4 + \
5"

eval(ifade)

veya şundan bahsetmiyorum:

ifade = """(2,
3)"""

eval(ifade)
2 Beğeni

İki satır bu kodun neresinde? Bu kodu iki satırlık yapan ne? “satırlık” ne demek?

Bildiğiniz gibi ; işareti kullanılarak bir sonraki satırda yapılacak işlem aynı satırda yapılabiliyor.

; işareti.

İki satırda yapılan işlem. İki satırlık işlem.

Bu iki satırda da yazılabilecek bir kodu tek satırda yazmamızı sağlıyor ise print("hello"); print("world") tek satırlık olur, tek satıra sığdırdık?

Bu kod niye 2 satırlık değil peki, yoksa öyle mi? :

";"

O zaman bu kod iki satırlık ve sizin tanımınıza uyuyor:

(1,
2)

Tek satıra iki satırda yapılan bir işlemi sığdırdık.

Değil.

Hayır uymuyor. Ve bence boşuna tartışıyoruz.

1 Beğeni

Ben sadece “n satırlık” ifadesinin anlamsız olduğunu düşündüğümü söylemeye çalıştım. Bunu bir fonksiyona verebileceğimiz parametreleri tarif ederken kullandınız ama bir tanım ifade etmediğini düşünüyorum.

İçinde birden fazla \n karakteri bulunan karakter dizilerini eval’e parametre olarak verebiliyoruz, satırdan anladığım da buydu.

1 Beğeni