Использование exec и eval в Python

Так я понял, что exec и eval и compile do. Но зачем мне их использовать? Я неясен в сценарии использования.

может ли кто-нибудь дать мне несколько примеров, чтобы я мог лучше оценить концепцию. Потому что я знаю, что это все теория.

8 ответов


я приведу пример, в котором я использовал eval и где я думаю, что это был лучший выбор.

я писал простую утилиту тестирования программного обеспечения ... что-то, чтобы проверить, соответствуют ли студенческие упражнения требованиям задания. Цель состояла в том, чтобы предоставить способ для простого файла конфигурации служить в качестве спецификации теста (обойти проблему "курицы и яйца" использования языка программирования для описания / документирования/реализации тестовых случаев для элементарных задания по программированию).

Я основал свою проводку на ConfigParser в стандартных библиотеках. Тем не менее, я хотел иметь возможность представлять произвольные строки Python (включая интерполяции \n, \t и особенно любые интерполированные шестнадцатеричные символы ASCII в значениях, считанных из них.

мое решение было try вокруг parsed_string=eval('''%s''' % cfg_read_item) затем try тройной версии с двойными кавычками ("""%s""") того же самого.

Это случай, когда альтернативой было бы написать (или найти предварительно написанный) синтаксический анализатор языка Python и выяснить, как включить и адаптировать его к моей программе. Риски минимальны (я не беспокоюсь, что студент представил код собирается обмануть мой парсер, вырваться, если его тюрьма, удалить все мои файлы, отправить мои номера кредитных карт в Румынию и так далее)*

*(отчасти потому, что я тестировал их под Linux из ненадежной учетной записи пользователя без головы).

как тут уже сказали, есть другие случаи использования, когда вы строите код из шаблона на основе входных данных и должны выполнить этот код (мета-Программирование). Вы всегда должны быть в состоянии выполнить эти задачи по-другому. Однако всякий раз, когда эта альтернатива влечет за собой усилия по кодированию, которые приближаются к написанию общего синтаксического анализатора/компилятора/интерпретатора языка программирования .... тогда eval может быть лучшим подходом.


стандартная библиотека имеет поучительный пример использования exec. сборники.namedtuple использует его для динамического построения класса.

template = '''class %(typename)s(tuple):
    '%(typename)s(%(argtxt)s)' \n
    __slots__ = () \n
    _fields = %(field_names)r \n
    def __new__(_cls, %(argtxt)s):
        'Create new instance of %(typename)s(%(argtxt)s)'
        return _tuple.__new__(_cls, (%(argtxt)s)) \n
    ...'''

   namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
                     OrderedDict=OrderedDict, _property=property, _tuple=tuple)
   try:
       exec template in namespace
   except SyntaxError, e:
       raise SyntaxError(e.message + ':\n' + template)

ast использует compile для создания абстрактных синтаксических деревьев из исходного кода Python. Они используются такими модулями, как pyflakes для анализа и проверки на Python.

def parse(expr, filename='<unknown>', mode='exec'):
    """
    Parse an expression into an AST node.
    Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
    """
    return compile(expr, filename, mode, PyCF_ONLY_AST)

вы Не нужно использовать их, и, на мой взгляд, вы должны избегать их.

Они полезны только в тех случаях, когда вы создаете код, который в итоге будет скорее всего считаться плохой практикой.

Если вы рассматриваете использование eval () для таких вещей, как математические выражения, вам было бы лучше санировать вход, прежде чем оценивать его. Вы никогда не знаете, какой "текст" пользователь отправляет, который может испортить приложения.


Я думаю, что у меня есть действительная польза. Я использую Python 3.2.1 внутри Blender 2.6.4 для изменения набора точек с координатами x,y (в Z-плоскости).

цель состоит в том, чтобы добавить концентрические кольца новых точек вокруг каждой существующей точки, причем кольца ведут себя как рябь (например, когда вы бросаете камень в пруд). Загвоздка в том, что я хочу, чтобы рябь конструктивно / деструктивно мешала друг другу, поэтому сначала я прохожу и строю "уравнение ряби", центрированное на каждом точка и суммирование всех уравнений пульсаций вместе в одно гигантское математическое уравнение, в которое я затем скормлю исходные точки, чтобы создать правильное z-значение, чтобы назначить каждому из них.

мой план состоит в том, чтобы добавить каждый дополнительный член в уравнении к предыдущему в виде строки, а затем использовать eval() для вычисления z-значения для нового набора точек.


вы просто спрашиваете пример? Вы можете написать простое приложение, которое читает из standard in и позволяет пользователю вводить различные выражения, такие как (4*2)/8 - 1. На других языках (Java, C++ и др.) это было бы почти невозможно оценить, но в python это просто, просто:

eval((4*2)/8 - 1)

Это, как говорится, если вы не будете осторожны, используя эти вещи могут быть очень опасно, поскольку они (по существу) позволяют пользователю огромное количество доступа.


Это используется в мета-программировании (когда программа пишет сама). Например, у вас есть животные разных видов, которые описываются разными классами: лев, тигр, лошадь, осел. И вы хотите имитировать скрещивание между ними, например, между Львом и Тигром. Когда вы пишете программу, вы не можете определить, как пользователь будет пересекать животных, но вы можете создавать новые классы животных на лету:

new_class_name = boy.class.to_str() + girl.class.to_str()
eval("class " + new_class_name + " extends " + boy.class.to_str() + ", " + girl.class.to_str())

P. S. Извините, я забыл Python некоторые. Так существует куча псевдокодов.


вот допустимый вариант использования. В промежуточном по Python paste (для веб-программирования) при возникновении исключения создается командная строка в браузере. Это работает с использованием таких методов. Кроме того, в Blender есть возможность анимировать значения с помощью выражений python, и это работает с использованием eval.