2.34. Dinamik kod¶
Üç yerleşik, bir Python kaynak dizesi alır ve çalıştırır: eval(), exec() ve compile(). Birlikte, kodun çalışma zamanında daha fazla kod oluşturmasına ve çalıştırmasına izin verirler – bu bazen tam olarak doğru araçtır, ama çok daha sık bir şekilde bir hata ve güvenlik açığı kaynağıdır.
Uyarı
Bu fonksiyonlar keyfi Python kodu çalıştırır. eval veya exec‘e kullanıcı girdisi geçirmek – kullanıcının düzenleyebileceği bir dosyadan gelen bir dize, ağ üzerinden alınan bir yük, bir REPL isteminde yazılan bir değer – o girdinin, çağıran betiğin yapabileceği her şeyi, cihazdaki her dosyayı silmeye kadar yapmasına izin verir. Bunları bilinçli olarak kullanın, asla otomatik çalışan kod içinde kullanmayın ve asla kontrolünüz dışındaki veriler üzerinde kullanmayın.
2.34.1. eval¶
eval(), tek bir ifadeyi çalıştırır ve değerini döndürür:
>>> eval("3 * 7")
21
>>> name = "OpenMV"
>>> eval("name.lower()")
'openmv'
İfade, varsayılan olarak çağıranın globals’ını ve locals’ını görür; bu yüzden ikinci örnekte name çözümlenir. Açık sözlükler geçirmek, değerlendirmeyi sandbox’lamanıza izin verir:
eval("a + b", {"__builtins__": None}, {"a": 1, "b": 2})
Sandbox’lanmış olsa bile eval tehlikelidir. Bu tür sandbox’lardan kaçmak için iyi bilinen teknikler vardır; güvenilmeyen girdi için yalnızca boş __builtins__ numarasına güvenmeyin.
2.34.2. exec¶
exec(), tek bir ifade yerine bir kod bloğu çalıştırır – deyimler, fonksiyon tanımları, döngüler – ve None döndürür:
exec("for i in range(3): print(i)")
Çıktı:
0
1
2
Blok, yerel ve global kapsam hakkında bazı uyarılarla birlikte, sonradan kullanılabilir hale gelen adlar tanımlayabilir. Bir fonksiyon içindeki exec nadiren yazarın beklediği gibi davranır; ona ihtiyacınız varsa modül düzeyinde çalıştırın.
2.34.3. compile¶
compile(), bir kaynak dizesini, daha sonra eval() veya exec()‘e geçirilebilecek bir kod nesnesine dönüştürür. Aynı kaynak birçok kez çalışacağında kullanın – ayrıştırma bir kez gerçekleşir, yürütme daha hızlı olur:
expr = compile("x * x", "<expr>", "eval")
for x in range(5):
print(eval(expr))
Çıktı:
0
1
4
9
16
Ortadaki argüman, kod bir hata fırlatırsa geri izlemelerde (traceback) görünen bir etikettir. Üçüncü argüman, tek bir ifade için "eval", bir blok için "exec" veya sonucunu yazdıran etkileşimli tarzda bir deyim için "single" olur.
2.34.4. Bunlara ne zaman başvurmalı¶
Neredeyse hiçbir zaman. Yeni başlayanların hayal ettiği çoğu kullanım durumunun daha güvenli alternatifleri vardır:
Bir yapılandırma dosyası okumak.
jsonkullanın – yapılandırılmış veri, yürütme yok.Kullanıcı tarafından yazılan sayısal bir değeri değerlendirmek. Ayrıştırmak için
int()/float(), ardından aritmetik kullanın. Kullanıcının gerçekten bir formül girmesi gerekiyorsa,evaldeğil, küçük bir ifade ayrıştırıcı kullanın.
Gerçekten eval / exec / compile‘a ihtiyacınız olduğunda, çağrı noktasını izole edin, çalıştırılmak üzere olan tam dizeyi günlüğe kaydedin ve kaynağı kodunuzdaki en şüpheli şey olarak ele alın.