Как мне выполнить строку, содержащую код Python в Python? - PullRequest
291 голосов
/ 31 марта 2009

Как мне выполнить строку, содержащую код Python в Python?

Ответы [ 13 ]

279 голосов
/ 31 марта 2009

Для утверждений используйте 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

Однако первым шагом должно быть спросить себя, действительно ли вам это нужно. Выполнение кода, как правило, должно быть последним средством: это медленно, безобразно и опасно, если он может содержать введенный пользователем код. Вы всегда должны сначала искать альтернативы, такие как функции более высокого порядка, чтобы увидеть, могут ли они лучше соответствовать вашим потребностям.

60 голосов
/ 31 марта 2009

В этом примере строка выполняется как код с использованием функции 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()
20 голосов
/ 29 июня 2013

Помните, что с версии 3 exec это функция!
поэтому всегда используйте exec(mystring) вместо exec mystring.

19 голосов
/ 18 февраля 2013

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

По сути, вы определяете пространство имен, в котором будет выполняться код.

11 голосов
/ 25 ноября 2010

eval() только для выражений, в то время как eval('x+1') работает, eval('x=1') не будет работать, например. В этом случае лучше использовать exec или даже лучше: попробуйте найти лучшее решение:)

9 голосов
/ 29 февраля 2016

Избегайте exec и eval

Использование exec и eval в Python вызывает неодобрение.

Есть лучшие альтернативы

С верхнего ответа (выделено мое):

Для заявлений используйте exec.

Если вам нужно значение выражения, используйте eval.

Однако первым шагом должно быть спросить себя, действительно ли вам это нужно. Выполнение кода обычно должно быть последним средством : Это медленно, безобразно и опасно, если он может содержать введенный пользователем код. Вы всегда должны сначала смотреть на альтернативы, такие как функции высшего порядка , чтобы увидеть, могут ли они лучше удовлетворить ваши потребности.

С Альтернативы exec / eval?

установить и получить значения переменных с именами в строках

[хотя eval] будет работать, обычно не рекомендуется использовать имена переменных, имеющие значение для самой программы.

Вместо этого лучше использовать дикт.

Это не идиоматично

С 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 месяцев, вы сами усложняете его.

9 голосов
/ 19 июля 2012

Вы выполняете код, используя exec, как в следующем сеансе IDLE:

>>> kw = {}
>>> exec( "ret = 4" ) in kw
>>> kw['ret']

4
4 голосов
/ 31 марта 2009

Выезд eval :

x = 1
print eval('x+1')
->2
3 голосов
/ 31 марта 2009

Наиболее логичным решением было бы использование встроенной функции eval () . Другое решение - записать эту строку во временный файл Python и выполнить ее.

3 голосов
/ 31 марта 2009

Использование eval .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...