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

Введение

Примеры

  • 0

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

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

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

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

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

    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 
  • 0

    Оценка выражения с помощью 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 
  • 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 не рассматривают ошибки в парсере как проблемы безопасности.

  • 1

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

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

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

Синтаксис

Параметры

Примечания