Python Language
Выполнение динамического кода с помощью `exec` и` eval`
Поиск…
Синтаксис
- eval (выражение [, globals = None [, locals = None]])
- Exec (объект)
- exec (объект, глобальные переменные)
- exec (объект, globals, locals)
параметры
аргументация | подробности |
---|---|
expression | Код выражения как строка или объект code |
object | Код оператора как строка или объект code |
globals | Словарь для использования для глобальных переменных. Если местные жители не указаны, это также используется для местных жителей. Если этот параметр опущен, используются globals() зоны вызова. |
locals | Объект сопоставления, который используется для локальных переменных. Если этот параметр опущен, вместо него используется тот, который передается для globals . Если оба они опущены, то globals() и locals() области вызова используются для globals и locals соответственно. |
замечания
В exec
, если globals
являются locals
(т.е. они относятся к одному и тому же объекту), код выполняется так, как если бы он находился на уровне модуля. Если globals
и locals
объекты являются отдельными объектами, код выполняется так, как если бы он находился в классе класса .
Если объект globals
передан, но не указывает ключ __builtins__
, тогда встроенные функции и имена Python автоматически добавляются в глобальную область. Чтобы подавить доступность таких функций, как print
или isinstance
в выполненной области, пусть globals
ключи имеют ключ __builtins__
отображаемый для значения None
. Однако это не функция безопасности.
Синтаксис Python 2 не должен использоваться; синтаксис Python 3 будет работать в Python 2. Таким образом, следующие формы устарели: <s>
-
exec object
-
exec object in globals
-
exec object in globals, locals
Оценка операторов с помощью 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, такие как строки, float и т. Д., Вы можете использовать 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.