Python'da Python kodu içeren bir dizeyi nasıl yürütebilirim?


358

Python'da Python kodu içeren bir dizeyi nasıl yürütebilirim?


5
Adil olmak gerekirse, diğer sorunun aksine, bu bir kopya değil. Ve diğerleri bundan çok daha temel sorular yayınladılar.
DNS

8
Elbette doğru cevap neredeyse her zaman “yapma!” Dır.
bobince

23
@S. Lott: SSS'yi yakın zamanda okumadınız mı? "Ayrıca kendi programlama sorunuzu sormak ve cevaplamak da gayet güzel, ama Tehlikede olduğunuzu varsayın: bunu bir soru şeklinde ifade edin". Bu kötü bir soru değil. +1
Devin Jeanpierre

49
@ S.Lott: Yapmıyorsun. Gerek yok. Soru zaten sitede değilse, o zaman adil bir oyundur (daha önce de belirtildiği gibi SSS'ye göre). Her soruyu OP'nin yardıma ihtiyacı varmış gibi cevaplayın. Yapmayabilirler, ama sorularını okuyan bir sonraki adam muhtemelen olacak. Sadece 2 sentim.
Bill the Lizard

1
Bunu yapmamanızı söyleyen herkese: Kesinlikle ihtiyacım olan bir durum var. Dağıtılmış işleme içerir.
sudo

Yanıtlar:


333

İ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.


1
ama 'exec' tarafından yürütülen kodun kapsamına ne dersiniz? yuvalanmış mı?
jondinham

22
Birinin 'exec' kullanmak istediği yaygın bir durum 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) = 42aynı şeyi ifade etmek için yazın.
ShreevatsaR

5
Exec nasıl python yorumlayıcıdan daha yavaştır?
Cris Stringfellow

7
@ShreevatsaR Bunu mu demek istediniz setattr(x, s, 42)? Denedim getattr(x, 2) = 42ve başarısız olducan't assign to function call: <string>, line 1
Tanner Semerad

7
@Tanner: Hmm. Evet setattr(x, s, 42), doğru sözdizimidir. Bu hatanın yakalanması çok uzun sürdü. Her neyse, asıl olmasıdır getattrve setattrbir alternatiftir execistediğin keyfi bir üyeyi almak için olduğunda dize tarafından aranır.
ShreevatsaR

68

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()

1
Stdout ve stderr'ı bu şekilde takas etmek beni çok sinirlendiriyor. bu büyük güvenlik sorunlarına neden olabilir gibi görünüyor. bunun bir yolu var mı?
Narcolapser

1
@Narcolapser exec( kod dizesinin güvenilir bir kaynaktan geldiğini bilmiyorsanız) hiç kullanmayla daha fazla ilgilenmem gerekir .
bruno desthuilliers

27

evalve execdoğ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 , evalve execiş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.


9
Eval'ı güvenli hale getirmek mümkün değildir: Eval gerçekten tehlikelidir . Benden kod alıp değerlendirirseniz, Python programınızı segfault edebilirim. Oyun bitti.
Ned Batchelder

3
@ v.oddou Alan'ın ifadesine "eval ve exec .. güvenli bir şekilde kullanılabilir." Bu yanlış. Birisi "bash güvenli bir şekilde kullanılabilir" derse, bu da yanlış olur. Bash tehlikelidir. Gerekli bir tehlikedir, ancak yine de tehlikelidir. Değerlendirmenin güvenli hale getirilebileceğini iddia etmek yanlıştır.
Ned Batchelder

1
@NedBatchelder evet gerçekten. ve işaret ettiğiniz bağlantı iyi bir malzemedir. güç ile sorumluluk gelir, bu yüzden mesele sadece değerlendirmenin potansiyel gücünün farkında olmaktır. ve bu iktidara karar verirsek = tehlike.
v.oddou

3
@NedBatchelder Python'da yazılmış birçok kod parçası da tehlikeli olabilir, ancak neden bunu varsayıyorsunuz evalveya execolarak 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 execdeğildir.
Thomas Baruchel

1
@ThomasBaruchel tekrar, eval veya exec güvenli hale getirilebilir fikrine karşı koymaktır. Özellikle bu cevap, küreselleri ve yerlileri kontrol etmenin onları güvenli bir şekilde kullanmayı mümkün kılacağını iddia ediyor. Bu yanlış. Exec ve eval komutlarını her kullandığınızda, hangi kodun yürütüldüğünü tam olarak bilmeniz gerekir. Eğer yapmazsanız, tehlikeli operasyonlara açıksınız demektir.
Ned Batchelder

21

Sürüm 3'ten itibaren execbir işlev olduğunu unutmayın!
bu yüzden her zaman exec(mystring)yerine kullanın exec mystring.


11

eval()yalnızca ifadeler içindir, ancak eval('x+1')çalışır, eval('x=1')örneğin çalışmaz. Bu durumda, kullanmak daha iyi exec, hatta daha iyi: daha iyi bir çözüm bulmaya çalışın :)


11

Kaçının execveeval

Kullanılması execve evalPython son derece hoş karşılanmaz.

Daha iyi alternatifler var

Ü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.

Deyimsel değil

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 execiçin bu aracı kullanmanız gerektiği anlamına gelmez.

Tehlikeli

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...

Okumak ve anlamak zor

Gönderen http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (vurgu mayın):

İlk olarak, execinsanları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.


"Benim en iyi tahminim, herhangi bir çift alt çizgi kullanamazsanız herhangi bir zarar veremez" - Çift alt çizgi içeren bir dize oluşturmak ve sonra eval dize çağırmak olabilir.
Stanley Bak

iyi bir tavsiye, sürece bir kod üreteci veya iş runner ya da benzeri ... çoğu insan muhtemelen yapıyor.
Erik Aronesty

Ben (bir yapılandırma-dosyasından göreli bir yol ithal etmek zorunda 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 reldirbu 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ı?
Marie. P.

9

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

1
Bu normal python'da çalışmaz. En azından python 3'te değil.
Thomas Ahle

6

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)


4

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())



1

Birkaç şey denedim, ama işe yarayan tek şey şuydu:

temp_dict = {}
exec("temp_dict['val'] = 10") 
print(temp_dict['val'])

çıktı:

10


0

En mantıklı çözüm, yerleşik eval () işlevini kullanmak olacaktır. Başka bir çözüm, bu dizeyi geçici bir python dosyasına yazmak ve yürütmektir.


0

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


1
Güvenliği nasıl yönettiniz? Müşterilerin bu ayrıcalığı kötüye kullanmayacağını nasıl biliyorsunuz?
JSBach
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.