Документация по Python

Динамическое выполнение кода с помощью exec и eval

В: Документация по Python

Оценка заявлений с exec

>>> code = """for i in range(5):\n    print('Hello world!')"""
>>> exec(code)
Hello world!
Hello world!
Hello world!
Hello world!
Hello world! 

Оценка выражения с помощью eval

>>> expression = '5 + 3 * a'
>>> a = 5
>>> result = eval(expression)
>>> result
20 

Прекомпиляция выражения для оценки его несколько раз

compile встроенную функцию можно использовать для прекомпилировать выражение к объекту кода; этот объект кода затем может быть передан в eval. Это ускорит повторное выполнение оцененного кода. Третий параметр compile должен быть строка 'eval' .

>>> code = compile('a * b + c', '<string>', 'eval')
>>> code
<code object <module> at 0x7f0e51a58830, file "<string>", line 1>
>>> a, b, c = 1, 2, 3
>>> eval(code)
5 

Оценка выражения с помощью eval с использованием пользовательских глобалов

>>> variables = {'a': 6, 'b': 7}
>>> eval('a * b', globals=variables)
42 

Как плюс, при этом код не может случайно ссылаться на имена, определенные снаружи:

 >>> eval('variables')
{'a': 6, 'b': 7}
>>> eval('variables', globals=variables)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'variables' is not defined

 

Использование defaultdict позволяет, например , имеющие неопределенные переменные , установленные на нуль:

>>> from collections import defaultdict
>>> variables = defaultdict(int, {'a': 42})
>>> eval('a * c', globals=variables)  # note that 'c' is not explicitly defined
0 

Оценка строки, содержащей литерал Python, с помощью ast.literal_eval

Если у вас есть строка , которая содержит Python литералы, такие как строки, поплавки и т.д., вы можете использовать ast.literal_eval оценить его значение вместо eval.Это имеет дополнительную функцию, позволяющую использовать только определенный синтаксис.

>>> import ast
>>> code = """(1, 2, {'foo': 'bar'})"""
>>> object = ast.literal_eval(code)
>>> object
(1, 2, {'foo': 'bar'})
>>> type(object)
<class 'tuple'>

Однако это небезопасно для выполнения кода, предоставленного ненадежным пользователем, и тривиально вывести из строя интерпретатор с тщательно продуманным вводом

>>> import ast
>>> ast.literal_eval('()' * 1000000)
[5]    21358 segmentation fault (core dumped)  python3

Здесь вход строка () повторяется один миллион раз, что приводит к сбою в CPython анализатор. Разработчики CPython не рассматривают ошибки в парсере как проблемы безопасности.

Выполнение кода, предоставленного ненадежным пользователем, используя exec, eval или ast.literal_eval

Это не представляется возможным использовать eval или exec для выполнения кода из ненадежного пользователя надежно. Даже ast.literal_eval склонен к сбоям в анализатор. Иногда можно защититься от выполнения вредоносного кода, но это не исключает возможности прямых сбоев в анализаторе или токенизаторе.

Чтобы оценить код ненадежного пользователя, вам нужно обратиться к какому-либо стороннему модулю или, возможно, написать свой собственный анализатор и собственную виртуальную машину на Python.

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.