Функція eval() оцінює вказаний вираз. Якщо вираз є допустимим Python-стейтментом, то його буде виконано.
Наприклад:
|
1 2 3 4 5 |
number = 9 # Функція eval() виконує операцію множення square_number = eval('number * number') print(square_number) |
Результат:
81
Синтаксис функції eval()
|
1 |
eval(вираз, globals=None, locals=None) |
Параметри функції eval()
Функція eval() приймає три параметри:
вираз — рядок, який аналізується та оцінюється як Python-вираз;
globals (не обов’язково) — словник;
locals (не обов’язково) — об’єкт для зіставлення. Словник — це стандартний тип зіставлення, який часто використовується в Python.
Значення, яке повертає функція eval()
Функція eval() повертає результат, отриманий з вираз.
Приклад №1: Як працює функція eval() в Python?
|
1 2 |
x = 1 print(eval('x + 1')) |
Результат:
2
Тут функція eval() оцінює вираз x + 1 та функція print() використовується для виводу цього значення на екран.
Приклад №2: Практичний приклад для демонстрації використання функції eval()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# Периметр квадрата def calculatePerimeter(l): return 4*l # Площа квадрата def calculateArea(l): return l*l expression = input("Type a function: ") for l in range(1, 5): if (expression == 'calculatePerimeter(l)'): print("If length is ", l, ", Perimeter = ", eval(expression)) elif (expression == 'calculateArea(l)'): print("If length is ", l, ", Area = ", eval(expression)) else: print('Wrong Function') break |
Результат:
Type a function: calculateArea(l)
If length is 1 , Area = 1
If length is 2 , Area = 4
If length is 3 , Area = 9
If length is 4 , Area = 16
Попередження при використанні функції eval()
Розглянемо ситуацію, коли ви використовуєте систему Unix (macOS, Linux) та імпортували модуль os. Модуль os надає портативний спосіб використання функцій операційної системи, таких як читання або запис у файл.
Якщо ви дозволите користувачам вводити значення за допомогою eval(input()), користувач зможе давати команди для зміни вмісту файлу або навіть видалення всіх файлів за допомогою команди os.system('rm -rf *').
Якщо ви використовуєте eval(input()) у своєму коді, то рекомендується перевірити, які змінні та функції доступні для використання користувачеві. Це можна зробити за допомогою функції dir():
|
1 2 |
from math import * print(eval('dir()')) |
Результат:
['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'os', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
Обмеження використання доступних функцій та змінних в eval()
Найчастіше всі доступні функції та змінні, які використовуються у вираз (перший параметр для eval()) можуть бути не потрібні. Можливо, вам необхідно обмежити використання цих функцій та змінних для eval(). Ви можете зробити це, передавши необов’язкові параметри globals та locals (словники) у функцію eval().
1. Коли пропущено параметри globals та locals
Якщо обидва параметри пропущені (як у попередніх прикладах), вираз виконується в поточній області видимості. Ви можете перевірити доступні змінні та функції, використовуючи наступний код:
|
1 |
print(eval('dir()') |
2. Передача параметра globals; параметр locals пропущено
Параметри globals та locals використовуються для глобальних та локальних змінних відповідно. Якщо словник locals не вказано, то за замовчуванням використовується словник globals. Це означає, що глобальні змінні будуть використовуватися як для глобальних, так і для локальних змінних.
Примітка: Ви можете перевірити поточні глобальні та локальні словники в Python за допомогою вбудованих функцій globals() та locals() відповідно.
Приклад №3: Передача пустого словника в якості параметра globals
|
1 2 3 4 5 |
from math import * print(eval('dir()', {})) # Викличе помилку print(eval('sqrt(25)', {})) |
Результат:
['__builtins__']
Traceback (most recent call last):
File "", line 5, in
print(eval('sqrt(25)', {}))
File "", line 1, in
NameError: name 'sqrt' is not defined
Якщо ви передали порожній словник в якості параметра globals, то доступний лише __builtins__ для вираз (перший параметр функції eval()).
Незважаючи на те, що ми імпортували модуль math в дану програму, вираз не може отримати доступ до будь-яких функцій, вказаних в модулі math.
Приклад №4: Забезпечення доступності конкретних методів
|
1 2 |
from math import * print(eval('dir()', {'sqrt': sqrt, 'pow': pow})) |
Результат:
['__builtins__', 'pow', 'sqrt']
Тут вираз може використовувати лише функції sqrt() та pow() разом з __builtins__.
Також можна змінити ім’я доступної функції для вираз на власний розсуд:
|
1 2 3 4 5 6 |
from math import * names = {'square_root': sqrt, 'power': pow} print(eval('dir()', names)) # Використання square_root у виразі print(eval('square_root(9)', names)) |
Результат:
['__builtins__', 'power', 'square_root']
3.0
У даній програмі calculate_root() обчислює квадратний корінь за допомогою функції sqrt(). Проте, спроба використовувати безпосередньо sqrt() викличе помилку.
Приклад №5: Обмеження використання __builtins__
Ви можете обмежити використання __builtins__ у вираз наступним чином:
|
1 |
eval(expression, {'__builtins__': None}) |
3. Передача словників globals та locals
Ви можете зробити необхідні функції та змінні доступними для використання, передавши словник locals. Наприклад:
|
1 2 3 4 |
from math import * a = 169 print(eval('sqrt(a)', {'__builtins__': None}, {'a': a, 'sqrt': sqrt})) |
Результат:
13.0
У цій програмі вираз може мати лише функцію sqrt() та змінну a. Всі інші змінні та функції недоступні.
Обмеження використання функції eval(), передаючи словники globals та locals, зробить код безпечним, коли ви використовуєте вхідні дані, надані користувачем для функції eval().
Примітка: Іноді функція eval() небезпечна навіть з обмеженими іменами. Коли об’єкт та його методи стають доступними, можна зробити майже все. Рішенням є перевірка користувацького вводу.
