Python'da Python kodu içeren bir dizeyi nasıl yürütebilirim?
Python'da Python kodu içeren bir dizeyi nasıl yürütebilirim?
Yanıtlar:
İfadeler için exec(string)
(Python 2/3) veya exec string
(Python 2) kullanın:
>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world
Bir ifadenin değerine ihtiyacınız olduğunda şunu kullanın eval(string)
:
>>> x = eval("2+2")
>>> x
4
Ancak, ilk adım kendinize gerçekten ihtiyacınız olup olmadığını sormak olmalıdır. Kod yürütmek genellikle son çare olarak olmalıdır: Kullanıcı tarafından girilen kod içeriyorsa yavaş, çirkin ve tehlikelidir. İhtiyaçlarınızı daha iyi karşılayıp karşılayamayacağını görmek için her zaman önce daha üst düzey işlevler gibi alternatiflere bakmalısınız.
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
, daha sonra yazabilecekleri vb exec ("x.%s = 42" % s)
. Bu yaygın durum için (yalnızca bir dizede saklanan bir nesnenin özelliğine erişmeniz gerektiğinde), çok daha hızlı, daha temiz ve daha güvenli bir işlev vardır getattr
: sadece getattr(x, s) = 42
aynı şeyi ifade etmek için yazın.
setattr(x, s, 42)
? Denedim getattr(x, 2) = 42
ve başarısız olducan't assign to function call: <string>, line 1
setattr(x, s, 42)
, doğru sözdizimidir. Bu hatanın yakalanması çok uzun sürdü. Her neyse, asıl olmasıdır getattr
ve setattr
bir alternatiftir exec
istediğin keyfi bir üyeyi almak için olduğunda dize tarafından aranır.
Bu örnekte, exec işlevi kullanılarak bir dize kod olarak yürütülür.
import sys
import StringIO
# create file-like string to capture output
codeOut = StringIO.StringIO()
codeErr = StringIO.StringIO()
code = """
def f(x):
x = x + 1
return x
print 'This is my output.'
"""
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
exec code
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print f(4)
s = codeErr.getvalue()
print "error:\n%s\n" % s
s = codeOut.getvalue()
print "output:\n%s" % s
codeOut.close()
codeErr.close()
exec
( kod dizesinin güvenilir bir kaynaktan geldiğini bilmiyorsanız) hiç kullanmayla daha fazla ilgilenmem gerekir .
eval
ve exec
doğru çözümdür ve daha güvenli bir şekilde kullanılabilirler.
Python'un referans kılavuzunda tartışıldığı ve bu öğreticide açıkça açıklandığı gibi , eval
ve exec
işlevleri, kullanıcının hangi küresel ve yerel işlevlerin ve değişkenlerin kullanılabilir olduğunu belirtmesine izin veren iki ekstra parametre alır.
Örneğin:
public_variable = 10
private_variable = 2
def public_function():
return "public information"
def private_function():
return "super sensitive information"
# make a list of safe functions
safe_list = ['public_variable', 'public_function']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
# add any needed builtins back in
safe_dict['len'] = len
>>> eval("public_variable+2", {"__builtins__" : None }, safe_dict)
12
>>> eval("private_variable+2", {"__builtins__" : None }, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_variable' is not defined
>>> exec("print \"'%s' has %i characters\" % (public_function(), len(public_function()))", {"__builtins__" : None}, safe_dict)
'public information' has 18 characters
>>> exec("print \"'%s' has %i characters\" % (private_function(), len(private_function()))", {"__builtins__" : None}, safe_dict)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'private_function' is not defined
Özünde, kodun yürütüleceği ad alanını tanımlıyorsunuz.
eval
veya exec
olarak kullanılmak üzere tasarlandınız exec(input("Type what you want"))
? Bir programın bir hesaplama sonucunda bir prosedür veya fonksiyon yazabileceği birçok durum vardır; sonuçta ortaya çıkan işlevler, iyi ve iyi yazılmış bir programın diğer bölümleri kadar güvenli ve hızlı (değerlendirildikten sonra) olacaktır. Güvenli olmayan bir program , programa yeni bir ayrıcalık tanımadığı için exec
, hasarı kendi başına yapan güvenli olmayan bir programdan daha tehlikeli exec
değildir.
exec
veeval
exec
ve eval
Python son derece hoş karşılanmaz.Üst cevaptan (benim vurgu):
İfadeler için kullanın
exec
.İfadenin değerine ihtiyacınız olduğunda, öğesini kullanın
eval
.Ancak, ilk adım kendinize gerçekten ihtiyacınız olup olmadığını sormak olmalıdır. Kod yürütmek genellikle son çare olarak olmalıdır : Kullanıcı tarafından girilen kod içeriyorsa yavaş, çirkin ve tehlikelidir. Bunların ihtiyaçlarınızı daha iyi karşılayıp karşılayamayacağını görmek için her zaman daha yüksek düzey işlevler gibi alternatiflere bakmalısınız .
Gönderen Alternatifler için exec / eval?
dizelerde isimleri olan değişkenlerin değerlerini ayarlama ve alma
[çalışırken
eval
], genellikle programın kendisi için bir anlam taşıyan değişken isimlerinin kullanılması tavsiye edilmez.Bunun yerine, bir diksiyon kullansan iyi olur.
Gönderen http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (vurgu benim)
Python PHP değil
Python deyimlerini atlatmaya çalışmayın, çünkü diğer bazı diller farklı şekilde yapar. Ad alanları bir sebepten dolayı Python'dadır ve sadece aracı verdiği
exec
için bu aracı kullanmanız gerektiği anlamına gelmez.
Gönderen http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (vurgu benim)
Tüm globalleri ve yerleşikleri kaldırsanız bile eval güvenli değildir!
Eval () 'i korumaya yönelik tüm bu girişimlerdeki sorun , bunların kara liste olmasıdır . Tehlikeli olabilecek şeyleri açıkça kaldırıyorlar. Bu kaybedilen bir savaştır, çünkü listeden sadece bir öğe kaldıysa, sisteme saldırabilirsiniz .
Peki, değerlendirme güvenli hale getirilebilir mi? Söylemesi zor. Bu noktada, en iyi tahminim, herhangi bir çift alt çizgi kullanamıyorsanız herhangi bir zarar veremeyeceğinizdir, bu yüzden çift alt çizgili herhangi bir dizeyi hariç tutarsanız güvende olursunuz. Olabilir...
Gönderen http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (vurgu mayın):
İlk olarak,
exec
insanların kodunuzu okumasını zorlaştırır . Ne olduğunu anlayabilmek için, sadece kodunuzu okumak zorunda değilim, kodunuzu okumak, hangi dizeyi oluşturacağınızı bulmak ve sonra sanal kodu okumak zorundayım. Yani, bir ekip üzerinde çalışıyorsanız veya açık kaynaklı yazılım yayınlıyorsanız veya StackOverflow gibi bir yerde yardım istiyorsanız, diğer kişilerin size yardım etmesini zorlaştırıyorsunuz. Ve bundan 6 ay sonra bu kodda hata ayıklama veya genişletme şansınız varsa, bunu doğrudan kendiniz için zorlaştırıyorsunuz.
cfg.yaml
): reldir : ../my/dir/
ve reldir = cfg[reldir]
. Ancak, bu python kodu hem Windows hem de Linux üzerinde çalışacağı için, farklı işletim sistemleri yol bölücülerine ayarlamak için buna ihtiyacım var; ya \\
da /
. Bu yüzden reldir : os.path.join('..','my','dir')
config dosyasında kullanıyorum. Ama bu sadece reldir
bu değişmez dizge olmak, değerlendirilmiyor olmasıyla sonuçlanır, bu yüzden bir dosyayı açamıyorum reldir
. Bir öneriniz var mı?
Yürütme kodunu aşağıdaki IDLE oturumunda olduğu gibi exec kullanarak gerçekleştirirsiniz:
>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']
4
Diğerlerinin de belirttiği gibi, "exec" ..
ancak, kodunuzun değişkenler içermesi durumunda, ona erişmek için "global" kullanabilirsiniz, ayrıca derleyicinin aşağıdaki hatayı yükseltmesini de önleyebilirsiniz:
NameError: 'p_variable' adı tanımlanmadı
exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)
Bahsetmeye değer, bir python dosyası çağırmak istiyorsanız ' exec
' erkek kardeşi de var execfile
. Korkunç IDE'leri olan bir üçüncü taraf paketinde çalışıyorsanız ve paketlerinin dışında kodlamak istiyorsanız, bazen iyi olur.
Misal:
execfile('/path/to/source.py)'
veya:
exec(open("/path/to/source.py").read())
Birkaç şey denedim, ama işe yarayan tek şey şuydu:
temp_dict = {}
exec("temp_dict['val'] = 10")
print(temp_dict['val'])
çıktı:
10
Tamam .. Bunun tam olarak bir cevap olmadığını biliyorum, ama muhtemelen benim gibi görünen insanlar için bir not. Farklı kullanıcılar / müşteriler için özel kod yürütmek istedim ama aynı zamanda exec / eval'den kaçınmak istedim. Başlangıçta her kullanıcı için bir veritabanında kod saklamak ve yukarıdakilere baktım.
Dosya sisteminde bir 'customer_filters' klasöründe dosyalar oluşturdum ve 'imp' modülünü kullandım, bu müşteri için filtre uygulanmadıysa, devam etti
import imp
def get_customer_module(customerName='default', name='filter'):
lm = None
try:
module_name = customerName+"_"+name;
m = imp.find_module(module_name, ['customer_filters'])
lm = imp.load_module(module_name, m[0], m[1], m[2])
except:
''
#ignore, if no module is found,
return lm
m = get_customer_module(customerName, "filter")
if m is not None:
m.apply_address_filter(myobj)
böylece customerName = "jj", customer_filters \ jj_filter.py dosyasından Apply_address_filter yürütür