Как выполнить строку, содержащую код Python в Python?
Как выполнить строку, содержащую код Python в Python?
Ответ 1
В примере строка выполняется как код с помощью функции 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()
Ответ 2
Для операторов используйте 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
Однако первым шагом должно стать спросить себя, действительно ли вам нужно. Исполняющий код обычно должен быть в крайнем случае: он медленный, уродливый и опасный, если он может содержать введенный пользователем код. Вы всегда должны сначала смотреть на альтернативы, такие как функции более высокого порядка, чтобы увидеть, могут ли они лучше соответствовать вашим потребностям.
Ответ 3
Помните, что из версии 3 exec
есть функция!
поэтому всегда используйте exec(mystring)
вместо exec mystring
.
Ответ 4
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
По сути вы определяете пространство имен, в котором будет выполняться код.
Ответ 5
eval()
предназначен только для выражений, а eval('x+1')
работает, eval('x=1')
не работает, например. В этом случае лучше использовать exec
или даже лучше: попытайтесь найти лучшее решение:)
Ответ 6
Вы выполняете выполнение кода с помощью exec, как и в следующем сеансе IDLE:
>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']
4
Ответ 7
Избегайте exec
и eval
Использование exec
и eval
в Python сильно неодобрительно.
Есть лучшие альтернативы
Из верхнего ответа (выделено мной):
Для операторов используйте
exec
.Когда вам нужно значение выражения, используйте
eval
.Однако первым шагом должно стать спросить себя, действительно ли вам нужно. Исполняющий код обычно должен быть в крайнем случае: он медленный, уродливый и опасный, если он может содержать введенный пользователем код. Вы всегда должны сначала искать альтернативы, такие как функции более высокого порядка, чтобы увидеть, могут ли они лучше соответствовать вашим потребностям.
задавать и получать значения переменных с именами в строках
[while
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() заключается в том, что они являются черными списками. Они явно удаляют вещи, которые могут быть опасными. Это проигравшая битва, потому что если в списке остался только один элемент, вы можете атаковать систему.
Итак, может ли быть безопасным? Тяжело сказать. На этом этапе я думаю, что вы не можете навредить, если не можете использовать двойные подчеркивания, поэтому, возможно, если вы исключите любую строку с двойными подчеркиваниями, вы будете в безопасности. Может быть...
Трудно читать и понимать
С http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (основное внимание):
Во-первых,
exec
затрудняет чтение человеком вашего кода. Чтобы выяснить, что происходит, мне не нужно просто читать ваш код, я должен прочитать ваш код, выяснить, какую строку он собирается генерировать, а затем прочитать этот виртуальный код. Итак, если вы работаете в команде или публикуете программное обеспечение с открытым исходным кодом или просите о помощи где-то вроде StackOverflow, вам становится труднее помочь другим людям. И если есть вероятность, что вы собираетесь отлаживать или расширять этот код через 6 месяцев, вам становится труднее для себя непосредственно.
Ответ 8
Отъезд eval:
x = 1
print eval('x+1')
->2
Ответ 9
Наиболее логичным решением было бы использовать встроенную функцию eval(). Другое решение - записать эту строку во временную python и выполнить его.
Ответ 10
Используйте eval.
Ответ 11
Хорошо. Я знаю, что это не совсем ответ, но, возможно, записка для людей, которые смотрят на это так, как я. Я хотел выполнить конкретный код для разных пользователей/клиентов, но также хотел избежать 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
Ответ 12
Стоит упомянуть, что " exec
brother существует, также называемый execfile
если вы хотите вызвать файл python. Иногда бывает хорошо, если вы работаете в стороннем пакете, в котором есть ужасная IDE, и вы хотите закодировать вне своего пакета.
Пример:
execfile('/path/to/source.py)'
или же:
exec(open("/path/to/source.py").read())