ฉันจะรันสตริงที่มีรหัส Python ใน Python ได้อย่างไร
ฉันจะรันสตริงที่มีรหัส Python ใน Python ได้อย่างไร
คำตอบ:
สำหรับข้อความสั่งให้ใช้exec(string)(Python 2/3) หรือexec string(Python 2):
>>> mycode = 'print "hello world"'
>>> exec(mycode)
Hello world
เมื่อคุณต้องการค่าของนิพจน์ให้ใช้eval(string):
>>> x = eval("2+2")
>>> x
4
อย่างไรก็ตามขั้นตอนแรกควรถามตัวเองว่าคุณต้องการจริงๆหรือไม่ โดยทั่วไปการเรียกใช้โค้ดควรเป็นตำแหน่งสุดท้าย: มันช้าน่าเกลียดและอันตรายหากสามารถมีรหัสที่ผู้ใช้ป้อนได้ คุณควรพิจารณาทางเลือกอื่นก่อนเช่นฟังก์ชั่นการสั่งซื้อที่สูงขึ้นเพื่อดูว่าสิ่งเหล่านี้สามารถตอบสนองความต้องการของคุณได้ดีขึ้นหรือไม่
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42ฯลฯ exec ("x.%s = 42" % s)ซึ่งพวกเขาก็อาจจะเขียนเป็น สำหรับกรณีทั่วไปนี้ (ที่คุณเพียงต้องการเข้าถึงคุณลักษณะของวัตถุที่เก็บไว้ในสตริง) มีฟังก์ชั่นที่เร็วกว่าสะอาดกว่าและปลอดภัยกว่าgetattrเพียงแค่เขียนgetattr(x, s) = 42ให้มีความหมายเหมือนกัน
setattr(x, s, 42)เหรอ? ฉันลองgetattr(x, 2) = 42แล้วมันล้มเหลวด้วยcan't assign to function call: <string>, line 1
setattr(x, s, 42)คือไวยากรณ์ที่ถูกต้อง แปลกใจที่มันใช้เวลานานมากสำหรับข้อผิดพลาดที่จะถูกจับ อย่างไรก็ตามประเด็นก็คือgetattrและsetattrเป็นทางเลือกexecเมื่อทุกสิ่งที่คุณต้องการคือการได้รับสมาชิกโดยพลการค้นหาสตริง
ในตัวอย่างสตริงจะถูกดำเนินการเป็นรหัสโดยใช้ฟังก์ชั่น exec
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เลย (เว้นแต่คุณจะรู้ว่าสตริงโค้ดนั้นมาจากแหล่งที่เชื่อถือได้)
evalและexecเป็นทางออกที่ถูกต้องและสามารถใช้ในที่ปลอดภัยยิ่งขึ้นลักษณะ
ตามที่กล่าวไว้ในคู่มืออ้างอิงของ Pythonและอธิบายอย่างชัดเจนในบทช่วยสอนนี้evalและexecฟังก์ชั่นใช้พารามิเตอร์พิเศษสองตัวที่อนุญาตให้ผู้ใช้ระบุฟังก์ชันและตัวแปรระดับโลกและระดับท้องถิ่น
ตัวอย่างเช่น:
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
ในสาระสำคัญคุณจะกำหนด namespace ที่รหัสจะถูกดำเนินการ
evalหรือexecตั้งใจจะใช้เป็นexec(input("Type what you want"))? มีหลายกรณีที่โปรแกรมอาจเขียนโพรซีเดอร์หรือฟังก์ชันอันเป็นผลมาจากการคำนวณ ฟังก์ชั่นที่ได้จะมีความปลอดภัยและรวดเร็ว (ประเมินผลครั้งเดียว) เป็นส่วนอื่น ๆ ของโปรแกรมที่ดีและเป็นลายลักษณ์อักษร โปรแกรมที่ไม่ปลอดภัยที่มีexecอันตรายไม่มากไปกว่าโปรแกรมที่ไม่ปลอดภัยซึ่งสร้างความเสียหายด้วยตัวเองเนื่องจากexecไม่ได้ให้สิทธิพิเศษใหม่แก่โปรแกรม
โปรดจำไว้ว่าจากเวอร์ชั่น 3 execเป็นฟังก์ชั่น!
จึงมักใช้แทนexec(mystring)exec mystring
eval()เป็นเพียงสำหรับการแสดงออกในขณะที่eval('x+1')ทำงานeval('x=1')จะไม่ทำงานเช่น ในกรณีนี้ควรใช้execหรือดีกว่า: ลองค้นหาวิธีแก้ปัญหาที่ดีกว่า :)
execและevalexecและevalใน Python นั้นทำให้ขมวดคิ้วอย่างมากจากคำตอบยอดนิยม (เน้นการเน้นของฉัน):
execสำหรับงบการใช้งาน
evalเมื่อคุณต้องการความคุ้มค่าของการแสดงออกการใช้อย่างไรก็ตามขั้นตอนแรกควรถามตัวเองว่าคุณต้องการจริงๆหรือไม่ โดยทั่วไปรหัสการดำเนินการควรเป็นตำแหน่งสุดท้าย : มันช้าน่าเกลียดและอันตรายหากสามารถมีรหัสที่ผู้ใช้ป้อนได้ คุณควรพิจารณาทางเลือกอื่นก่อนเช่นฟังก์ชั่นการสั่งซื้อที่สูงขึ้นเพื่อดูว่าสิ่งเหล่านี้สามารถตอบสนองความต้องการของคุณได้ดีขึ้นหรือไม่
กำหนดและรับค่าของตัวแปรด้วยชื่อในสตริง
[ขณะ
eval] จะใช้งานได้โดยทั่วไปจะไม่แนะนำให้ใช้ชื่อตัวแปรที่มีความหมายกับโปรแกรมเองให้ใช้ dict แทน
จากhttp://lucumr.pocoo.org/2011/2/1/exec-in-python/ (เน้นที่เหมือง)
Python ไม่ใช่ PHP
อย่าพยายามหลีกเลี่ยงสำนวน Python เพราะภาษาอื่นบางภาษาใช้มันแตกต่างกัน เนมสเปซอยู่ใน Python ด้วยเหตุผลเพียงเพราะมันให้เครื่องมือ
execมันไม่ได้หมายความว่าคุณควรใช้เครื่องมือนั้น
จากhttp://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (เน้นที่เหมือง)
ดังนั้น Eval จึงไม่ปลอดภัยแม้ว่าคุณจะลบรูปทรงกลมทั้งหมดและตัวในออก!
ปัญหาที่มีทั้งหมดของเหล่านี้พยายามที่จะป้องกัน EVAL () ที่พวกเขามีบัญชีดำ พวกเขาลบสิ่งที่อาจเป็นอันตรายได้อย่างชัดเจน นั่นคือการต่อสู้ที่พ่ายแพ้เพราะหากมีเพียงหนึ่งไอเท็มที่เหลืออยู่ในรายการคุณสามารถโจมตีระบบได้ได้
ดังนั้น eval สามารถทำให้ปลอดภัยหรือไม่ ยากที่จะพูด. ณ จุดนี้การคาดเดาที่ดีที่สุดของฉันคือคุณไม่สามารถทำอันตรายใด ๆ ได้หากคุณไม่สามารถใช้เครื่องหมายขีดล่างคู่ใด ๆ ได้ดังนั้นหากคุณไม่รวมสตริงใด ๆ ที่มีการขีดเส้นใต้สองเท่าคุณจะปลอดภัย อาจจะ...
จากhttp://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (เน้นที่เหมือง):
ก่อนอื่น
execทำให้มนุษย์อ่านรหัสของคุณยากขึ้น เพื่อที่จะทราบว่าเกิดอะไรขึ้นฉันไม่เพียงแค่ต้องอ่านรหัสของคุณฉันต้องอ่านรหัสของคุณคิดออกว่าจะสร้างสตริงอะไรจากนั้นอ่านรหัสเสมือนนั้น ดังนั้นหากคุณกำลังทำงานเป็นทีมหรือเผยแพร่ซอฟต์แวร์โอเพนซอร์ซหรือขอความช่วยเหลือจากที่ไหนสักแห่งเช่น StackOverflow คุณจะทำให้คนอื่นยากที่จะช่วยเหลือคุณ และถ้ามีโอกาสที่คุณจะทำการดีบั๊กหรือขยายโค้ดนี้อีก 6 เดือนนับจากนี้คุณจะทำให้มันยากขึ้นสำหรับตัวคุณเองโดยตรง
cfg.yaml) และreldir : ../my/dir/ reldir = cfg[reldir]อย่างไรก็ตามเนื่องจากโค้ดไพ ธ อนนี้จะทำงานทั้งบน Windows และ Linux ฉันต้องการสิ่งนี้เพื่อปรับให้เข้ากับตัวแบ่งพา ธ ของระบบปฏิบัติการที่แตกต่างกัน อย่างใดอย่างหนึ่งหรือ\\ /ดังนั้นฉันจะใช้reldir : os.path.join('..','my','dir')ในไฟล์กำหนดค่า แต่ตอนนี้ผลเฉพาะในการเป็นนี้สตริงตัวอักษรที่ไม่ถูกประเมินดังนั้นฉันไม่สามารถเปิดไฟล์ในreldir reldirคุณมีข้อเสนอแนะหรือไม่?
คุณดำเนินการโค้ดให้สำเร็จโดยใช้ exec เช่นเดียวกับเซสชัน IDLE ต่อไปนี้:
>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']
4
ดังที่คนอื่น ๆ พูดถึงมันคือ "exec" ..
แต่ในกรณีที่โค้ดของคุณมีตัวแปรคุณสามารถใช้ "global" เพื่อเข้าถึงมันได้เช่นกันเพื่อป้องกันคอมไพเลอร์เพื่อเพิ่มข้อผิดพลาดดังต่อไปนี้:
NameError: ชื่อ 'p_variable' ไม่ได้ถูกกำหนดไว้
exec('p_variable = [1,2,3,4]')
global p_variable
print(p_variable)
เป็นมูลค่าการกล่าวขวัญว่าexecพี่ชายของอยู่ที่เรียกว่าexecfileถ้าคุณต้องการเรียกไฟล์หลาม บางครั้งก็เป็นสิ่งที่ดีหากคุณทำงานในแพ็คเกจของบุคคลที่สามซึ่งมี IDE อยู่ในตัวและคุณต้องการโค้ดนอกแพ็คเกจของพวกเขา
ตัวอย่าง:
execfile('/path/to/source.py)'
หรือ:
exec(open("/path/to/source.py").read())
ฉันพยายามทำบางสิ่งเล็กน้อย แต่สิ่งเดียวที่ใช้ได้คือ:
temp_dict = {}
exec("temp_dict['val'] = 10")
print(temp_dict['val'])
เอาท์พุท:
10
วิธีการแก้ปัญหาเชิงตรรกะมากที่สุดคือการใช้ฟังก์ชั่นeval () ในตัวโซลูชั่นอื่น ๆ คือการเขียนสตริงนั้นไปยังไฟล์ไพ ธ อนชั่วคราวและดำเนินการ
ตกลง .. ฉันรู้ว่านี่ไม่ใช่คำตอบที่แน่ชัด แต่อาจเป็นเพราะคนที่มองสิ่งนี้เหมือนฉัน ฉันต้องการรันโค้ดเฉพาะสำหรับผู้ใช้ / ลูกค้าที่แตกต่างกัน แต่ยังต้องการหลีกเลี่ยง exec / eval ตอนแรกฉันพยายามเก็บรหัสไว้ในฐานข้อมูลสำหรับผู้ใช้แต่ละคนและทำตามขั้นตอนด้านบน
ฉันลงเอยด้วยการสร้างไฟล์ในระบบไฟล์ภายในโฟลเดอร์ 'customer_filters' และใช้โมดูล 'imp' หากไม่มีตัวกรองสำหรับลูกค้ารายนั้นมันเพิ่งจะดำเนินการ
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)
ดังนั้น customerName = "jj" จะดำเนินการ Apply_address_filter จากไฟล์ customer_filters \ jj_filter.py