Содержание статьи

Функция eval выполняет строку Python-кода как выражение и возвращает результат. Она принимает строку с кодом и необязательные аргументы globals и locals, позволяя ограничивать область видимости и контролировать доступ к переменным и функциям. Это особенно полезно при динамическом формировании выражений во время работы программы.
Eval часто применяют для вычисления математических выражений из пользовательского ввода, например, «12 / (2 + 4)» возвращает 2.0 без написания отдельной функции для каждого случая. Также можно использовать eval для преобразования строк в Python-объекты, например словари или списки, если они корректно оформлены.
При использовании eval важно ограничивать доступ к опасным объектам. Передача в аргументы globals и locals специально подготовленных словарей позволяет контролировать, какие функции и переменные доступны во время выполнения. Это снижает риск выполнения вредоносного кода при обработке пользовательских данных.
Для задач, где нужны только базовые типы данных, безопаснее применять ast.literal_eval. Она позволяет работать с числами, строками, списками, кортежами, словарями и булевыми значениями без возможности выполнения произвольного кода. Eval целесообразно использовать только тогда, когда необходим полный контроль над выражениями и области видимости.
Что делает eval с переданной строкой кода

Функция eval принимает строку, содержащую выражение на Python, и возвращает результат её вычисления. Например, eval(«10 / 2») вернёт 5.0, а eval(«‘Python’ + ‘ 3.11′») объединит строки в «Python 3.11». Eval выполняет только выражения, которые возвращают значение, и не обрабатывает инструкции вроде if, for или def.
При вызове eval строка сначала синтаксически анализируется, затем компилируется во внутреннее представление Python и выполняется в заданной области видимости. По умолчанию используются текущие глобальные и локальные переменные. Для ограничения доступа к функциям и переменным можно передать словари globals и locals, содержащие только безопасные объекты.
Eval поддерживает работу с числами, строками, списками, кортежами, словарями и логическими выражениями. Например, eval(«{‘x’: 1, ‘y’: 2}[‘y’]») вернёт 2. Также можно использовать встроенные функции и методы объектов, если они доступны в текущей области видимости.
При работе с внешними данными рекомендуется проверять строку перед передачей в eval. Непроверенный ввод может выполнить опасный код. Безопаснее создавать ограниченные словари globals и locals, включающие только нужные функции и переменные для вычислений.
Синтаксис и базовые примеры использования eval
Функция eval имеет синтаксис eval(expression, globals=None, locals=None), где expression – строка с Python-выражением, globals и locals – словари для ограничения области видимости. Если словари не переданы, eval использует текущие глобальные и локальные переменные.
Простейший пример: eval(«2 + 3 * 4») вернёт 14. Для работы с переменными можно передать словарь: eval(«a + b», {«a»: 5, «b»: 7}) вернёт 12. В таком случае значения переменных берутся только из переданного словаря, игнорируя внешние объекты.
Eval поддерживает строки, списки, кортежи и словари. Например, eval(«[1, 2, 3] + [4]») вернёт [1, 2, 3, 4], а eval(«{‘x’: 1, ‘y’: 2}[‘y’]») вернёт 2. Методы объектов можно использовать, если они доступны в области видимости: eval(«‘python’.upper()») вернёт «PYTHON».
Для динамических вычислений из пользовательского ввода рекомендуется передавать ограниченные словари globals и locals, включающие только допустимые функции и переменные. Это предотвращает доступ к опасным методам и встроенным объектам.
Ограничение области видимости при вызове eval
Функция eval по умолчанию использует текущие глобальные и локальные переменные для вычисления выражения. Это позволяет строке кода обращаться к любым доступным объектам, что создаёт потенциальный риск выполнения опасных операций.
Чтобы ограничить область видимости, в eval можно передавать словари globals и locals. В globals указываются разрешённые глобальные переменные и функции, а locals контролирует локальные имена. Например, eval(«x + y», {«x»: 2}, {«y»: 3}) вернёт 5, при этом доступ к остальным переменным из текущего пространства имён будет заблокирован.
Ограничение области видимости особенно важно при работе с пользовательским вводом. Без него eval сможет вызвать встроенные функции вроде open или __import__, что создаёт угрозу безопасности. Для вычислений достаточно включить только необходимые функции и переменные.
Применение безопасного словаря для globals и locals позволяет использовать eval для математических вычислений, работы со строками и структурами данных без риска выполнения произвольного кода. Например: safe_globals = {«abs»: abs, «max»: max} и eval(«max([1, -5, 3])», safe_globals) вернёт 3.
Использование eval для вычисления математических выражений

Функция eval позволяет динамически вычислять строковые математические выражения без необходимости писать отдельные функции для каждого случая. Она обрабатывает стандартные операторы и скобки, возвращая результат выражения.
Примеры применения:
- eval(«3 + 5 * 2») вернёт 13, учитывая приоритет операций.
- eval(«(10 — 2) / 4») вернёт 2.0, корректно вычисляя выражение с дробями.
- eval(«2**3 + 1») вернёт 9, используя возведение в степень.
Для работы с переменными можно передавать словарь globals с необходимыми значениями:
- eval(«a * b + c», {«a»: 3, «b»: 4, «c»: 2}) вернёт 14.
- Можно ограничить доступ к внешним функциям и объектам, передавая пустой словарь для locals, чтобы предотвратить выполнение небезопасного кода.
Рекомендации при использовании eval для вычислений:
- Перед обработкой пользовательского ввода фильтровать запрещённые символы или команды.
- Использовать ограниченные словари globals и locals для безопасного доступа только к нужным функциям, например abs или round.
- Для простых выражений чисел и арифметики можно рассматривать ast.literal_eval как более безопасную альтернативу.
Работа с переменными и словарями через eval

Функция eval позволяет динамически обращаться к переменным и ключам словарей, переданным в качестве области видимости. Это особенно удобно для обработки данных, сформированных во время выполнения программы.
Примеры использования с переменными:
- eval(«x + y», {«x»: 10, «y»: 5}) вернёт 15, используя значения из переданного словаря.
- Можно изменять локальные переменные, передавая словарь в locals: eval(«z * 2», {}, {«z»: 7}) вернёт 14.
Примеры работы со словарями:
- data = {«a»: 3, «b»: 4}
- eval(«data[‘a’] + data[‘b’]», {«data»: data}) вернёт 7, позволяя вычислять значения по ключам динамически.
- Для вложенных словарей можно использовать выражения вида eval(«config[‘section’][‘option’]», {«config»: config}).
Рекомендации при работе с переменными и словарями через eval:
- Передавать только необходимые переменные в словарях globals и locals, чтобы ограничить доступ к остальной области видимости.
- Проверять имена переменных и ключи словарей на допустимые значения, особенно при работе с пользовательским вводом.
- Для вычислений, включающих только числовые или структурированные данные, рассматривать ast.literal_eval как более безопасную альтернативу.
Риски безопасности при применении eval

Функция eval выполняет переданную строку как Python-код, что делает её потенциально опасной при обработке данных из внешних источников. Любой пользовательский ввод может содержать команды, способные изменить файлы, получить доступ к системным ресурсам или вызвать импорт нежелательных модулей.
Примеры опасных выражений:
- eval(«__import__(‘os’).system(‘rm -rf /’)») – выполнение системной команды.
- eval(«open(‘secret.txt’).read()») – чтение конфиденциальных файлов.
- eval(«().__class__.__bases__[0].__subclasses__()») – обход ограничений доступа к объектам Python.
Рекомендации по снижению рисков:
- Использовать ограниченные словари globals и locals, включающие только разрешённые функции и переменные.
- Проверять и фильтровать строки перед передачей в eval, исключая ключевые слова и встроенные функции, способные повредить систему.
- Для безопасной работы с простыми структурами данных использовать ast.literal_eval, который разрешает только числа, строки, списки, кортежи, словари и булевы значения.
- Избегать применения eval для исполнения кода, поступающего напрямую от пользователей, если невозможно полностью контролировать ввод.
Альтернативы eval для безопасного исполнения кода

Для динамического вычисления выражений без риска выполнения произвольного кода можно использовать встроенный модуль ast. Функция ast.literal_eval преобразует строку в объекты Python, разрешая только числа, строки, списки, кортежи, словари и булевы значения. Она не выполняет функции и методы, что исключает возможность выполнения опасных команд.
Пример использования:
ast.literal_eval(«[1, 2, 3]») вернёт список [1, 2, 3], а попытка выполнить ast.literal_eval(«open(‘file.txt’)») вызовет исключение SyntaxError.
Для более сложных выражений можно применять безопасные интерпретаторы или парсеры, например:
- Модуль numexpr – вычисляет математические выражения, поддерживая операции с массивами и скалярами, без доступа к системе.
- Библиотеки для шаблонного вычисления, такие как simpleeval, которые позволяют задавать допустимые функции и переменные.
- Использование собственных функций-парсеров для специфических задач, когда нужно контролировать каждый допустимый оператор и тип данных.
При выборе альтернатив важно ограничивать область видимости и явно задавать доступные функции и переменные. Это предотвращает выполнение нежелательных операций и повышает безопасность работы с динамическим кодом.
Вопрос-ответ:
Можно ли использовать eval для выполнения сложных циклов и функций?
Функция eval обрабатывает только выражения, которые возвращают значение. Она не выполняет инструкции вроде for, while или определения функций через def. Для циклов и функций нужно использовать exec или создавать функции напрямую в коде. Eval подходит для вычисления математических выражений, обращения к переменным или словарям и вызова методов объектов, доступных в текущей области видимости.
Как безопасно использовать eval с данными, введёнными пользователем?
Чтобы снизить риск, строки для eval необходимо проверять и фильтровать, исключая ключевые слова и функции, способные работать с файловой системой или импортом модулей. Кроме того, рекомендуется передавать ограниченные словари globals и locals, включающие только нужные переменные и функции. Для обработки простых числовых выражений лучше использовать ast.literal_eval, так как он не позволяет выполнять методы или системные команды.
Можно ли через eval работать с динамически создаваемыми словарями и списками?
Да, eval позволяет обращаться к ключам словарей и элементам списков, переданных в область видимости. Например, eval(«data[‘key’]», {«data»: {«key»: 42}}) вернёт 42. Аналогично можно вычислять выражения с элементами списка: eval(«lst[0] + lst[1]», {«lst»: [3, 5]}) вернёт 8. Для вложенных структур следует учитывать корректность ключей и индексов.
Какие функции и объекты нельзя использовать в eval без ограничений?
Не следует позволять eval доступ к встроенным функциям, которые могут изменять систему или получать доступ к файлам, например open, exec, __import__, а также объектам типа os или sys. Без ограничений eval может выполнить произвольный код, включая удаление файлов или изменение системных настроек. Для безопасного использования стоит передавать собственные словари globals и locals, ограничивающие доступ к критическим объектам.
В каких случаях лучше использовать ast.literal_eval вместо eval?
Если требуется обработка только чисел, строк, списков, кортежей, словарей и булевых значений, ast.literal_eval является более безопасным вариантом. Она не выполняет функции и методы, что исключает возможность запуска вредоносного кода. Это подходит для преобразования пользовательских данных, например строковых представлений списков или словарей, в реальные Python-объекты.
Можно ли использовать eval для динамического изменения переменных и выполнения операций с ними?
Да, eval позволяет вычислять выражения, включающие переменные, переданные через словари globals и locals. Например, eval(«a + b», {«a»: 5, «b»: 3}) вернёт 8. Также можно обращаться к ключам словарей или элементам списков: eval(«config[‘timeout’] * 2», {«config»: {«timeout»: 10}}) вернёт 20. При этом eval не создаёт новые переменные в глобальном пространстве автоматически — для изменения существующих переменных нужно обновлять их словари вручную. Для безопасного использования следует ограничивать доступ к функциям и объектам, которые могут изменить систему или вызвать нежелательные действия, передавая в globals и locals только необходимые элементы.
