Использование exec и eval в Python - PullRequest
8 голосов
/ 11 ноября 2010

Итак, я понял, что делают exec и eval, а также compile. Но зачем мне их использовать? Я неясен сценарий использования.

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

Ответы [ 8 ]

5 голосов
/ 11 ноября 2010

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

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

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

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

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

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

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

4 голосов
/ 11 ноября 2010

В стандартной библиотеке есть поучительный пример использования exec. collection.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)
3 голосов
/ 11 ноября 2010

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)
1 голос
/ 30 ноября 2012

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

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

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

1 голос
/ 11 ноября 2010

Вам не нужно , чтобы использовать их, и, по моему мнению, вам следует избегать их.

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

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

0 голосов
/ 11 ноября 2010

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

0 голосов
/ 11 ноября 2010

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

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. С. Извините, я немного забыл Python. Так что есть куча псевдокода.

0 голосов
/ 11 ноября 2010

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

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

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

...