如何将未加引号的Python函数/ lambda转换为AST? 2.6

时间:2009-09-23 21:34:07

标签: python abstract-syntax-tree

这似乎应该很容易,但我无法在任何地方找到答案 - 也无法自己派生出答案。你如何将未引用的python函数/ lambda转换为AST?

这是我希望能够做到的。

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)

5 个答案:

答案 0 :(得分:10)

一般情况下,你不能。例如,2 + 2是一个表达式 - 但是如果将它传递给任何函数或方法,则传递的参数只是数字4,无法恢复计算它的表达式。函数源代码有时可以恢复(虽然不适用于lambda),但“未加引号的Python表达式”得到评估所以你得到的只是表达式值的对象。

你想解决什么问题?可能还有其他可行的方法。

编辑:tx到OP进行澄清。没有办法为lambda或其他一些极端情况做这件事,但正如我提到的函数源代码有时可以被恢复......:

import ast
import inspect

def f():
  return 23

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

print ast.dump(tree)

inspect.getsource如果无法获取您传递的任何对象的源代码,则会引发IOError。我建议你将解析和getsource调用包装成一个辅助函数,它可以接受一个字符串(并且只是解析它)或一个函数(并尝试获取它,可能在IOError情况下提供更好的错误)。

答案 1 :(得分:6)

如果只能访问函数/ lambda,那么只有编译的python字节码。无法从字节码重构精确的Python AST,因为编译过程中存在信息丢失。但是你可以分析字节码并为此创建AST。 GeniuSQL中有一个这样的分析器。我还有一个小概念证明,它分析字节码并从中创建SQLAlchemy子元素。

我用于分析的过程如下:

  1. 将代码拆分为具有潜在参数的操作码列表。
  2. 通过遍历操作码找到代码中的基本块,并且每次跳转都会在跳转后和跳转目标之前创建基本块边界
  3. 从基本块创建控制流图。
  4. 使用抽象解释跟踪堆栈和SSA形式的变量赋值,浏览所有基本块。
  5. 要创建输出表达式,只需获取计算出的SSA返回值。
  6. 我已粘贴proof of conceptexample code using it。这是非干净的快速入侵代码,但如果你愿意,你可以自由地构建它。如果你决定用它做一些有用的东西,请留言。

答案 2 :(得分:5)

The Meta library允许您在许多情况下恢复源代码,但有一些例外,例如comprehensions和lambdas。

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

答案 3 :(得分:1)

您无法从编译的字节码生成AST。你需要源代码。

答案 4 :(得分:0)

你的lambda表达式是一个函数,它有很多信息,但我认为它还没有与之相关的源代码。我不确定你能得到你想要的东西。