2009-09-23 3 views
7

Кажется, что это должно быть легко, но я не могу найти ответ нигде - и не могу получить его сам. Как вы превращаете неупорядоченную функцию python/lambda в AST?Как вы превращаете неупорядоченную функцию Python/лямбда в AST? 2.6

Вот что я хотел бы иметь.

import ast 
class Walker(ast.NodeVisitor): 
    pass 
    # ... 

# note, this doesnt work as ast.parse wants a string 
tree = ast.parse(lambda x,y: x+y) 

Walker().visit(tree) 
+0

@Ants Aasma предложение было ближе всего к тому, что я надеялся, хотя, кажется, намного сложнее, чем я ожидал, и я думаю, более хрупкие WRT различные версии Python (если изменения байт-кода). GeniuSQL также выглядит многообещающим. Выключить, чтобы провести некоторое тестирование! – Chris

+0

Кроме того, вы нашли это: http://code.activestate.com/recipes/442447/ – Chris

ответ

6

Если вы только получили доступ к функции/лямбда, у вас есть только скомпилированный байт-код python. Точный Python AST не может быть восстановлен из байт-кода, потому что в процессе компиляции есть потеря информации. Но вы можете проанализировать байт-код и создать для этого AST. В GeniuSQL есть один такой анализатор. У меня также есть небольшое доказательство концепции, в которой анализируется байт-код и создается классовые элементы SQLAlchemy.

Процесс я использовал для анализа заключается в следующем:

  1. Split код в список кодов операций с потенциальными аргументами.
  2. Найти базовые блоки в коде, пройдя коды операций, и для каждого прыжка создайте базовую границу блока после прыжка и до цели перехода
  3. Создайте граф потока управления из базовых блоков.
  4. Пройдите все базовые блоки с абстрактным стеком отслеживания интерпретации и переменными назначениями в форме SSA.
  5. Чтобы создать выходное выражение, просто получите рассчитанное значение возврата SSA.

Я вставил свои proof of concept и example code using it. Это не очищает быстро взломанный код, но вы можете использовать его, если хотите. Оставьте заметку, если вы решите сделать что-то полезное.

+0

А, я вижу. Таким образом, вы берете скомпилированный байт-код и создаете свой собственный АСТ, подходящий для генерации SQL или других грамматик. Это довольно блестяще (и далеко за пределами моего уровня мастерства :). Я еще раз рассмотрю ваш код и GenuiuSQL. Я не понимал, что существует еще один маршрут, отличный от стандартного модуля lib '' ast'', и я думаю, что это ослепило меня. Благодарю. – Chris

+0

Ссылки на dpaste теперь устарели :( –

0

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

10

В общем, вы не можете. Например, 2 + 2 является выражением, но если вы передаете его какой-либо функции или методу, передаваемый аргумент - это просто номер 4, не способ восстановить то, из какого выражения он был вычислен. Исходный код функции иногда может быть восстановлен (хотя и не для lambda), но «выражение без кавычек Python» получает , оцененный, поэтому вы получаете только объект, который является значением выражения.

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

Редактировать: tx to OP для уточнения. Там нет никакого способа сделать это для lambda или некоторых других случаев угловых, но, как я уже функция исходного кода иногда может быть восстановлен ...:

import ast 
import inspect 

def f(): 
    return 23 

tree = ast.parse(inspect.getsource(f)) 

print ast.dump(tree) 

inspect.getsource поднимает IOError, если он не может получить исходный код для любого объект, которым вы его передаете. Я предлагаю вам обернуть разбор и запрос источника в вспомогательную функцию, которая может принимать строку (и просто анализирует ее) ИЛИ функцию (и пытается получить источник на ней, возможно, давая лучшие ошибки в случае IOError).

+0

Прошу прощения - я вижу, что это выражение является неправильным термином для использования. Он был удален из вопроса. В общем, я пытаюсь превратить АСТ в другую грамматику. Конкретные примеры: из приведенного func/lambda, сгенерируйте инструкцию SQL или javascript couchdb map/reduce view или mongodb query dict и т. Д. Я полагаю, что некорректно не является строгим требованием, но будет чище. – Chris

+0

Спасибо за ваши предложения и код. Я не знал о insepect.getsource. Я могу попытаться использовать метод байт-кода и этот метод inspect.getsource для сравнения. – Chris

1

Вы не можете генерировать AST из скомпилированного байт-кода. Вам нужен исходный код.

4

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

import meta, ast 
source = ''' 
a = 1 
b = 2 
c = (a ** b) 
''' 

mod = ast.parse(source, '<nofile>', 'exec') 
code = compile(mod, '<nofile>', 'exec') 

mod2 = meta.decompile(code) 
source2 = meta.dump_python_source(mod2) 

assert source == source2 

 Смежные вопросы

  • Нет связанных вопросов^_^