Чтобы быть справедливым, в отличие от другого вопроса, этот не дубликат. А другие опубликовали гораздо более простые вопросы, чем этот.
DNS
8
Правильный ответ, конечно, почти всегда «не надо!».
Бобинц
23
@S. Лотт: Вы недавно не читали FAQ? «Также вполне нормально задавать и отвечать на свой собственный вопрос программирования, но притворяться, что вы находитесь в опасности: сформулируйте это в форме вопроса». Это не плохой вопрос. +1
Девин Жанпьер
49
@ S.Lott: нет. Вам не нужно. Если вопрос еще не на сайте, значит, это честная игра (согласно FAQ, как уже указывалось). Просто отвечайте на каждый вопрос, как будто ОП нуждается в помощи. Возможно, нет, но следующий парень, который читает их вопрос, вероятно, будет. Просто мои 2 цента.
Билл Ящерица
1
На все, что вы говорите, не делать этого: у меня есть случай, когда мне абсолютно необходимо. Это включает в себя распределенную обработку.
>>> mycode ='print "hello world"'>>>exec(mycode)Hello world
Когда вам нужно значение выражения, используйте eval(string):
>>> x = eval("2+2")>>> x4
Тем не менее, первым шагом должно быть спросить себя, действительно ли вам это нужно. Выполнение кода, как правило, должно быть последним средством: он медленный, безобразный и опасный, если он может содержать введенный пользователем код. Вы всегда должны сначала смотреть на альтернативы, такие как функции высшего порядка, чтобы увидеть, могут ли они лучше удовлетворить ваши потребности.
а как насчет объема кода, выполняемого exec? это вложенный?
Jondinham
21
Распространенный случай, когда кто-то хочет использовать «exec» - это что-то вроде if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42etc, которое они могут затем записать как exec ("x.%s = 42" % s). Для этого общего случая (когда вам нужен только доступ к атрибуту объекта, который хранится в строке), есть гораздо более быстрая, более чистая и безопасная функция getattr: просто пишите, getattr(x, s) = 42чтобы означать одно и то же.
ShreevatsaR
5
Как exec медленнее, чем интерпретатор python?
Крис Стрингфеллоу
6
@ ShreevatsaR ты не имеешь ввиду setattr(x, s, 42)? Я пытался, getattr(x, 2) = 42и это не удалось сcan't assign to function call: <string>, line 1
Таннер Семерад
6
@ Таннер: Хм. Да, действительно setattr(x, s, 42)правильный синтаксис. Удивило, что так долго эта ошибка была обнаружена. Во всяком случае, дело в том , что getattrи setattrявляется альтернативой , execкогда все , что вы хотите, чтобы получить произвольный элемент, посмотрел на строке.
ShreevatsaR
68
В этом примере строка выполняется как код с использованием функции exec.
import sys
importStringIO# 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()
меняя stdout и stderr, я очень нервничаю. похоже, это может вызвать огромные проблемы с безопасностью. есть ли способ обойти это?
Narcolapser
1
@Narcolapser, вы должны быть более заинтересованы в использовании exec(если только вы не знаете, что строка кода взята из надежного источника).
Bruno Desthuilliers
27
evalи execявляются правильным решением, и они могут быть использованы более безопасным способом.
Как уже говорилось в справочном руководстве Пайтон и четко объяснено в этом учебнике, evalи execфункции принимают два дополнительных параметра , которые позволяют пользователю определить , какие глобальные и локальные функции и переменные доступны.
Например:
public_variable =10
private_variable =2def 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'isnot 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'isnot defined
По сути, вы определяете пространство имен, в котором будет выполняться код.
Невозможно сделать eval безопасным: Eval действительно опасен . Если вы возьмете у меня код и оцените его, я могу сделать ошибку в вашей программе на Python. Игра окончена.
Нед Бэтчелдер
3
@ v.oddou Я отвечал на заявление Алана: «eval и exec .. могут быть использованы безопасным образом». Это неверно Если кто-то сказал: «bash можно использовать безопасным образом», это также было бы ложным. Баш опасен. Это необходимая опасность, но тем не менее опасная. Утверждать, что eval можно сделать безопасным, просто неправильно.
Нед Бэтчелдер
1
@NedBatchelder да, действительно. и ссылка, на которую вы указываете, является хорошим материалом. С силой приходит ответственность, поэтому смысл просто в том, чтобы осознавать потенциальную силу оценки. и если мы решим, что сила = опасность.
v.oddou
3
@NedBatchelder Многие куски кода , написанного на Python может быть опасно , как хорошо, но почему вы предполагая , что evalи execпредназначены для использования в качестве exec(input("Type what you want"))? Есть много случаев, когда программа может написать процедуру или функцию в результате вычисления; Результирующие функции будут такими же безопасными и быстрыми (после оценки), как и любая другая часть хорошей и хорошо написанной программы. Небезопасная программа, содержащая execее, не более опасна, чем небезопасная программа, которая сама наносит ущерб, поскольку execне дает ей никаких новых привилегий.
Томас Барухель
1
Снова @ThomasBaruchel, моя цель состоит в том, чтобы противостоять идее, что eval или exec могут быть сделаны безопасными. В частности, в этом ответе утверждается, что контроль над глобальными и местными жителями позволит безопасно использовать их. Это неверно. Каждый раз, когда вы используете exec и eval, вы должны точно знать, какой код выполняется. Если вы этого не сделаете, то вы открыты для опасных операций.
Нед Бэтчелдер
21
Помните, что с версии 3 execэто функция!
так что всегда используйте exec(mystring)вместо exec mystring.
eval()только для выражений, хотя eval('x+1')работает, eval('x=1')не будет работать, например. В этом случае лучше использовать execили даже лучше: попробуйте найти лучшее решение :)
Использование execи evalв Python весьма неодобрительно.
Есть лучшие альтернативы
С верху ответ (акцент мой):
Для заявлений используйте exec.
Когда вам нужно значение выражения, используйте eval.
Тем не менее, первым шагом должно быть спросить себя, действительно ли вам это нужно. Выполнение кода, как правило, должно быть последним средством : он медленный, безобразный и опасный, если он может содержать введенный пользователем код. Вы всегда должны сначала смотреть на альтернативы, такие как функции высшего порядка , чтобы увидеть, могут ли они лучше удовлетворить ваши потребности.
Не пытайтесь обойти идиомы Python, потому что другой язык делает это по-другому. Пространства имен есть в Python по причине и только потому, что она дает вам инструмент, execно это не значит, что вы должны использовать этот инструмент.
Так что Eval не является безопасным, даже если вы удалите все глобальные и встроенные!
Проблема со всеми этими попытками защитить eval () заключается в том, что они являются черными списками . Они явно удаляют вещи, которые могут быть опасными. Это проигрышная битва, потому что если в списке остается только один элемент, вы можете атаковать систему .
Итак, можно ли сделать eval безопасным? Тяжело сказать. На данный момент, я думаю, вы не можете причинить вреда, если не можете использовать двойные подчеркивания, поэтому, возможно, если вы исключите любую строку с двойным подчеркиванием, вы в безопасности. Может быть...
Во-первых, execлюдям труднее читать ваш код . Чтобы понять, что происходит, мне нужно не просто прочитать ваш код, я должен прочитать ваш код, выяснить, какую строку он будет генерировать, а затем прочитать этот виртуальный код. Поэтому, если вы работаете в команде, или публикуете программное обеспечение с открытым исходным кодом, или просите о помощи где-то, например, в StackOverflow, вам будет труднее помогать другим людям. И если есть шанс, что вы собираетесь отлаживать или расширять этот код через 6 месяцев, вы сами усложняете его.
«Я думаю, что вы не можете причинить никакого вреда, если не можете использовать двойные подчеркивания» - вы можете создать строку, содержащую двойные подчеркивания, а затем вызвать eval этой строки.
Стэнли Бак,
Хороший совет, если вы не пишете генератор кода, или работника или что-то подобное ... что большинство людей здесь, вероятно, делают.
Эрик Аронести
Я должен импортировать относительный путь из config-file ( cfg.yaml): reldir : ../my/dir/ и reldir = cfg[reldir]. Тем не менее, так как этот код Python должен работать как в Windows, так и в Linux, мне нужно это настроить для различных разделителей пути операционных систем; либо \\ или /. Поэтому я использую reldir : os.path.join('..','my','dir')в файле конфигурации. Но это только приводит к тому, reldirчто эта буквальная строка не вычисляется, поэтому я не могу открыть файл в reldir. У вас есть предложение?
Мари. П.
9
Вы выполняете код, используя exec, как в следующем сеансе IDLE:
Стоит отметить, что этот execбрат тоже существует, execfileесли вы хотите вызвать файл python. Иногда это хорошо, если вы работаете в стороннем пакете, в который включены ужасные IDE, и вы хотите писать код вне их пакета.
Наиболее логичным решением было бы использование встроенной функции eval (). Другое решение - записать эту строку во временный файл Python и выполнить ее.
Хорошо ... Я знаю, что это не совсем ответ, но, возможно, записка для людей, которые смотрят на это так, как я. Я хотел выполнить определенный код для разных пользователей / клиентов, но также хотел избежать exec / eval. Сначала я хотел сохранить код в базе данных для каждого пользователя и выполнить вышеизложенное.
Я закончил тем, что создал файлы в файловой системе в папке customer_filters и использовал модуль imp, если для этого клиента не применен фильтр, он просто продолжил
import imp
def get_customer_module(customerName='default', name='filter'):
lm =Nonetry:
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 isnotNone:
m.apply_address_filter(myobj)
поэтому customerName = "jj" будет выполнять apply_address_filter из файла customer_filters \ jj_filter.py
Ответы:
Для операторов используйте
exec(string)
(Python 2/3) илиexec string
(Python 2):Когда вам нужно значение выражения, используйте
eval(string)
:Тем не менее, первым шагом должно быть спросить себя, действительно ли вам это нужно. Выполнение кода, как правило, должно быть последним средством: он медленный, безобразный и опасный, если он может содержать введенный пользователем код. Вы всегда должны сначала смотреть на альтернативы, такие как функции высшего порядка, чтобы увидеть, могут ли они лучше удовлетворить ваши потребности.
источник
if s=='foo': x.foo = 42 elif s=='bar': x.bar = 42
etc, которое они могут затем записать как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.
источник
exec
(если только вы не знаете, что строка кода взята из надежного источника).eval
иexec
являются правильным решением, и они могут быть использованы более безопасным способом.Как уже говорилось в справочном руководстве Пайтон и четко объяснено в этом учебнике,
eval
иexec
функции принимают два дополнительных параметра , которые позволяют пользователю определить , какие глобальные и локальные функции и переменные доступны.Например:
По сути, вы определяете пространство имен, в котором будет выполняться код.
источник
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?
Это не идиоматично
С http://lucumr.pocoo.org/2011/2/1/exec-in-python/ (выделено мной)
Это опасно
С http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html (выделено мной)
Трудно читать и понимать
От http://stupidpythonideas.blogspot.it/2013/05/why-evalexec-is-bad.html (выделено мной):
источник
cfg.yaml
):reldir : ../my/dir/
иreldir = cfg[reldir]
. Тем не менее, так как этот код Python должен работать как в Windows, так и в Linux, мне нужно это настроить для различных разделителей пути операционных систем; либо\\
или/
. Поэтому я используюreldir : os.path.join('..','my','dir')
в файле конфигурации. Но это только приводит к тому,reldir
что эта буквальная строка не вычисляется, поэтому я не могу открыть файл вreldir
. У вас есть предложение?Вы выполняете код, используя exec, как в следующем сеансе IDLE:
источник
Как уже упоминалось, это "exec" ..
но, если ваш код содержит переменные, вы можете использовать «глобальный» для доступа к нему, а также, чтобы компилятор не вызвал следующую ошибку:
источник
Используйте Eval .
источник
Стоит отметить, что этот
exec
брат тоже существует,execfile
если вы хотите вызвать файл python. Иногда это хорошо, если вы работаете в стороннем пакете, в который включены ужасные IDE, и вы хотите писать код вне их пакета.Пример:
execfile('/path/to/source.py)'
или:
exec(open("/path/to/source.py").read())
источник
Проверьте Eval :
источник
Я перепробовал несколько вещей, но единственное, что работало, было следующее:
вывод:
10
источник
Наиболее логичным решением было бы использование встроенной функции eval (). Другое решение - записать эту строку во временный файл Python и выполнить ее.
источник
Хорошо ... Я знаю, что это не совсем ответ, но, возможно, записка для людей, которые смотрят на это так, как я. Я хотел выполнить определенный код для разных пользователей / клиентов, но также хотел избежать exec / eval. Сначала я хотел сохранить код в базе данных для каждого пользователя и выполнить вышеизложенное.
Я закончил тем, что создал файлы в файловой системе в папке customer_filters и использовал модуль imp, если для этого клиента не применен фильтр, он просто продолжил
поэтому customerName = "jj" будет выполнять apply_address_filter из файла customer_filters \ jj_filter.py
источник