Использование eval в Python?
Есть eval()
Функция в Python, на которую я наткнулся во время игры. Я не могу представить себе случай, когда эта функция нужна, за исключением, может быть, синтаксического сахара. Кто-нибудь может привести пример?
13 ответов
eval
а также exec
удобный быстрый и грязный способ получить некоторый исходный код динамически, может быть, немного изменить его, а затем выполнить его, но вряд ли он когда-либо будет лучшим способом, особенно в производственном коде, в отличие от "быстрого и грязного" прототипы и пр.
Например, если бы мне пришлось иметь дело с такими динамическими исходниками Python, я бы достал модуль ast - ast.literal_eval
НАМНОГО безопаснее, чем eval
(вы можете вызвать его непосредственно в строковой форме выражения, если оно одноразовое и зависит только от простых констант, или сделать node = ast.parse(source)
сначала сохраните node
где-то, возможно, возьмите его с подходящими посетителями, например для поиска переменных, затем literal_eval
узел) - или, однажды приведя узел в надлежащую форму и проверив его на наличие проблем безопасности, я мог бы compile
это (получая объект кода) и построить новый объект функции из этого. Гораздо менее просто (за исключением того, что ast.literal_eval
так же просто, как eval
для самых простых случаев!) но безопаснее и предпочтительнее в коде производственного качества.
Для многих задач, которые я видел, люди (ab-) используют exec
а также eval
для, мощные встроенные модули Python, такие как getattr
а также setattr
, индексируя в globals()
, &c, предоставляют предпочтительные и на самом деле часто более простые решения. Для конкретных целей, таких как анализ JSON, библиотечные модули, такие как json
лучше (например, см. комментарий SilentGhost к ответу на шум в ушах на этот самый вопрос). И т. Д., И т. Д.
Статья в Википедии оeval
довольно информативен, и детализирует различные варианты использования.
Вот некоторые варианты использования:
- Оценка математических выражений
- Начальная загрузка компилятора
- Сценарии (динамические языки в целом очень подходят для этого)
- Репетиторы языка
Возможно, вы захотите использовать его, чтобы позволить пользователям вводить свои собственные "скриптлеты": небольшие выражения (или даже небольшие функции), которые можно использовать для настройки поведения сложной системы.
В этом контексте, и если вам не нужно слишком заботиться о последствиях для безопасности (например, у вас есть образованная база пользователей), тогда eval() может быть хорошим выбором.
В прошлом я использовал eval() для добавления интерфейса отладки в мое приложение. Я создал службу telnet, которая поместила вас в среду запущенного приложения. Входные данные проходили через eval(), поэтому вы можете интерактивно запускать команды Python в приложении.
В программе, которую я когда-то написал, у вас был входной файл, в котором вы могли указывать геометрические параметры как в виде значений, так и в виде выражений Python предыдущих значений, например:
a=10.0
b=5.0
c=math.log10(a/b)
Синтаксический анализатор python прочитал этот входной файл и получил окончательные данные, оценивая значения и выражения с помощью eval().
Я не утверждаю, что это хорошее программирование, но мне не нужно было управлять ядерным реактором.
Я использую его как быстрый JSON-парсер...
r='''
{
"glossary": {
"title": "example glossary"
}
}
'''
print eval(r)['glossary']['title']
Вы можете использовать eval в декораторе:
#this replaces the original printNumber with a lambda-function,
#which takes no arguments and which calls the old function with
#the number 10
@eval("lambda fun: lambda: fun(10)")
def printNumber(i: int) -> None:
print("The number is %i", i)
#call
printNumber()
в то время как вы не можете использовать сложные выражения, такие как
@lambda fun: lambda: fun(10)
def ...
ни
@(lambda fun: lambda: fun(10))
def ...
Вы не можете использовать лямбда-выражение там, потому что декоратор должен быть либо идентификатором:
@myModule.functionWithOneArg
или вызов функции:
@functionReturningFunctionWithOneArg(any, "args")
Вы видите, что вызов функции eval со строкой имеет здесь правильный синтаксис, а лямбда-выражение - нет. (-> https://docs.python.org/3/reference/compound_stmts.html)
Я только что нашел хорошее применение eval. Я писал набор тестов для некоторого кода и создал класс Test, где каждый метод представлял собой тест, который нужно запустить. Мне нужен был способ, чтобы я мог запускать все тестовые методы без необходимости вызывать каждый метод отдельно. Итак, я написал что-то довольно грязное.
class Test:
def __init__(self, *args):
#bs
def test1(self):
#bs
def test2(self):
#bs
if __name__ == "__main__":
import argparse
#argparse bs
test = Test(*bs_args)
for func in (i for i in dir(test) if i[0] != '_' and i not in test.__dict__):
print(eval('test.{func}()'.format(func = func)))
Динамическая оценка произвольных тестовых случаев довольно крутая. Мне просто нужно написать метод, и после сохранения я могу включить метод в свой набор тестов. Что касается кода, я в основном просто проверяю методы, определенные в тестовом объекте, и проверяю, что они не являются "магическими" методами или атрибутами python по умолчанию для тестового объекта. После этого я могу предположить, что они являются методами и могут быть оценены.
Eval - это способ взаимодействия с интерпретатором Python из программы. Вы можете передавать литералы в eval, и он оценивает их как выражения Python.
Например -
print eval("__import__('os').getcwd()")
вернул бы текущий рабочий каталог.
ура
eval()
обычно не очень полезен. Одна из немногих вещей, которые я использовал для этого (ну, это было exec()
на самом деле, но это довольно похоже) позволяло пользователю создавать сценарии приложения, которое я написал на Python. Если бы он был написан на чем-то вроде C++, мне бы пришлось встроить интерпретатор Python в приложение.
eval() для одного предложения, а exec() для нескольких.
обычно мы используем их для добавления или посещения некоторых скриптов, таких как bash shell.
из-за того, что они могут запускать некоторые байтовые сценарии в памяти, если у вас есть важные данные или сценарий, который вы можете декодировать и распаковать в "секрет", делайте все, что вы хотите.
У меня был случай, когда я использовал eval в сочетании с базой данных informix. По какой-то причине запрос вернул строку, подобную этой
query_result = "['1', '2', '3']"
Я просто использовал eval для результата запроса, поэтому python интерпретировал его как список строк.
[int(i) for i in eval(query_result)]
> [1,2,3]
Я не мог изменить базу данных, поэтому это был быстрый (и грязный) способ получить целые числа.
Я использовал его для ввода значений переменных в основную программу:
test.py var1 = 2 var2 = True
...
var1=0
var2=False
for arg in sys.argv[1:]:
exec(arg)
Грубый способ разрешить использование ключевых слов в основной программе. Если есть лучший способ, дайте мне знать!
Я использую exec
создать систему плагинов в Python.
пытаться: exec ("from " + plugin_name + " import Plugin") myplugin = плагин (module_options, config=config) кроме ImportError, сообщение: фатальный ("Нет такого модуля" + plugin_name + \ " (или нет конструктора плагинов) в моем пути Python:" + str (message)) кроме исключения: фатальный ("Module " + plugin_name + "не может быть загружен: " + \ str(sys.exc_type) + ": " + str(sys.exc_value) + \ ".\n Может быть, отсутствует или ошибочен?"
С плагином вроде:
Плагин класса: def __init__ (self): проходить запрос def (self, arg):...
Вы сможете назвать это как:
result = myplugin.query ("что-то")
Я не думаю, что вы можете иметь плагины в Python без exec
/eval
,