Метод Python exec — выполняет динамически созданную программу. Синтаксис данного метода достаточно простой.
exec(object, globals, locals)
Параметры метода exec()
Метод exec() принимает три аргумента. Один обязательный аргумент, и два опциональных.
- object — Строка, либо объект
- globals — таблицы символов (словарь)
- locals — локальная таблица символов. Не забываем, что словарь в Python это стандартный и один из самых часто используемых типов данных.
Возвращаемые значения метода exec():
Данный метод не возвращает никаких значений, по мимо значения None.
Пример 1. Как работает метод exec()?
program = 'a = 5\nb=10\nprint("Sum =", a+b)'
exec(program)
#Результат
15
В данном случае строка program передается в exec(). Параметры globals() и locals() в данном случае не используются, о них мы поговорим чуть позднее.
Пример 2. Разрешаем пользователю вводить данные
program = input('Enter a program:')
exec(program)
Небольшое примечание. Если вы хотите что бы пользователь мог вводить многострочный код Python, вы можете использовать метод compile() перед методом exec().
Будьте осторожны при использовании метода exec().
Представим себе простую ситуацию. Вы являетесь пользователем Unix систем. В свое программе вы импортировали модуль os. Как вы уже знаете, модуль os можете обеспечить доступ к функциям операционной системы. Чтение файлов, запись файлов, удаление и прочие.
В том случае, если вы не фильтруете вводимые данные пользователем, в exec(input()), пользователь может ввести любые данные, которые могут привести к неожиданным последствиям.
os.system('rm -rf *')
К примеру данная команда способна удалить все ваши файлы. Поэтом настоятельно вам рекомендую, в случае использования данного метода, проверить какие данные может вводить пользователь. С помощью метода dir() вы можете посмотреть какие переменные и методы доступны.
from math import *
exec('print(dir())')
Ограничения доступных методов и переменных в exec()
Вы можете ограничить использование различных переменных и методов, передавая их в необязательные параметры globals и locals для метода ecex(). Вы можете проверить доступные методы и переменные следующим кодом.
exec('print(dir())')
В параметрах globals и locals хранятся данные по локальным и глобальным переменным и методам соответственно. Если например не указан параметр locals, то по умолчанию значение globals будет использован как для локальных и глобальных переменных.
Передача пустого словаря в качестве параметра globals
from math import *
exec('print(dir())', {})
# Получим исключение
# exec('print(sqrt(9))', {})
В случае, если мы передаем пустой словарь как globals, несмотря на то, что у нас импортирован математический модуль math, пытаясь получить доступ к любой из функций, мы получим ошибку исключения.
Мы можем обеспечить доступность определенных методов следующим образом.
from math import *
exec('print(dir())', {'sqrt': sqrt, 'pow': pow})
# Объект имеет доступ к методу sqrt
exec('print(sqrt(9))', {'sqrt': sqrt, 'pow': pow})
В данном случае, выполняемый exec() может иметь sqrt() pow() методы. Так же, мы можем переименовать название методов на свое усмотрение.
from math import *
exec('print(dir())', {'squareRoot': sqrt, 'pow': pow})
# Доступ к методу squareRoot
exec('print(squareRoot(9))', {'squareRoot': sqrt, 'pow': pow})
Теперь в нашей программе метод squareroot() вычисляет корень аналогично методу sqrt(), но в тоже время, если мы попытаемся использовать sqrt() то получим ошибку исключения.
Передача глобального и локального словаря
Мы можем сделать так, что бы необходимые функции и переменные были доступными для использования, передав словарь locals.
from math import *
globalsParameter = {'__builtins__' : None}
localsParameter = {'print': print, 'dir': dir}
exec('print(dir())', globalsParameter, localsParameter)
В данном случае, как вы можете видеть два стандартных метода print и dir, могут быть выполнены с помощью метода exec(). Необходимо отметить, что метод exec() выполняет код, и по мимо значения None, не возвращает ничего. Вы не можете использовать к примеру return.