Здесь много хороших ответов, но ни один не описывает использование eval()
в контексте его globals
и locals
kwargs, то есть eval(expression, globals=None, locals=None)
(см. Документы для eval
здесь ).
Они могут использоваться для ограничения методов, доступных через метод eval
. Например, если вы загрузите новый интерпретатор Python, locals()
и globals()
будут одинаковыми и будут выглядеть примерно так:
>>>globals()
{'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__doc__': None,
'__spec__': None, '__builtins__': <module 'builtins' (built-in)>,
'__package__': None, '__name__': '__main__'}
В модуле builtins
, безусловно, есть методы, которые могут нанести значительный ущерб системе. Но можно заблокировать все, что мы не хотим, доступное. Давайте возьмем пример. Допустим, мы хотим создать список, представляющий домен доступных ядер в системе. Для меня у меня 8 ядер, поэтому я бы хотел список [1, 8]
.
>>>from os import cpu_count
>>>eval('[1, cpu_count()]')
[1, 8]
Аналогично доступно все __builtins__
.
>>>eval('abs(-1)')
1
Хорошо. Таким образом, мы видим один метод, который мы хотим раскрыть, и пример одного (из многих, который может быть гораздо более сложного) метода, который мы не хотим раскрывать. Итак, давайте заблокируем все.
>>>eval('[1, cpu_count()]', {'__builtins__':None}, {})
TypeError: 'NoneType' object is not subscriptable
Мы эффективно заблокировали все методы __builtins__
и, таким образом, повысили уровень защиты нашей системы. На этом этапе мы можем начать добавлять обратно методы, которые нам действительно нужны.
>>>from os import cpu_count
>>>exposed_methods = {'cpu_count': cpu_count}
>>>eval('cpu_count()', {'__builtins__':None}, exposed_methods)
8
>>>eval('abs(cpu_count())', {'__builtins__':None}, exposed_methods)
TypeError: 'NoneType' object is not subscriptable
Теперь у нас есть метод cpu_count
, который блокирует все, что нам не нужно. На мой взгляд, это супер мощный и явно из сферы других ответов, а не общего осуществления. Существует множество вариантов использования чего-то подобного, и при условии правильного обращения с ним я лично чувствую, что eval
может быть безопасно использован для большой стоимости.
N.B.
Что еще здорово в этих kwargs
, так это то, что вы можете начать использовать сокращение для своего кода. Допустим, вы используете eval как часть конвейера для выполнения некоторого импортированного текста. Текст не обязательно должен содержать точный код, он может соответствовать какому-либо формату файла шаблона и при этом выполнять все, что вы захотите. Например:
>>>from os import cpu_count
>>>eval('[1,cores]', {'__builtins__': None}, {'cores': cpu_count()})
[1, 8]