ฉันจะรันสตริงที่มีรหัส 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
และeval
exec
และ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