8

这似乎应该很容易,但我无法在任何地方找到答案——我自己也无法得出答案。如何将未引用的 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)
4

5 回答 5

10

一般来说,你不能。例如,2 + 2是一个表达式——但如果你将它传递给任何函数或方法,传递的参数只是数字4,无法恢复它是从哪个表达式计算出来的。函数源代码有时可以恢复(虽然不是 a lambda),但是“未引用的 Python 表达式”会被评估,所以你得到的只是表达式值的对象。

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

编辑:发送给 OP 以进行澄清。对于lambda其他一些极端情况,没有办法做到这一点,但正如我提到的,函数源代码有时可以恢复......:

import ast
import inspect

def f():
  return 23

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

print ast.dump(tree)

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

于 2009-09-23T22:03:27.373 回答
6

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

我用来分析的过程如下:

  1. 将代码拆分为具有潜在参数的操作码列表。
  2. 通过遍历操作码找到代码中的基本块,并为每次跳转在跳转之后和跳转目标之前创建一个基本块边界
  3. 从基本块创建控制流图。
  4. 使用 SSA 形式的抽象解释跟踪堆栈和变量分配遍历所有基本块。
  5. 要创建输出表达式,只需获取计算的 SSA 返回值。

我已经粘贴了我的概念证明使用它的示例代码。这是不干净的快速组合代码,但如果您愿意,您可以自由地在其上构建。如果您决定从中做出有用的事情,请留下便条。

于 2009-09-24T08:52:11.153 回答
5

Meta 库允许您在许多情况下恢复源代码,但有一些例外,例如理解和 lambda。

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
于 2012-08-30T19:23:35.463 回答
2

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

于 2009-09-23T23:33:28.367 回答
0

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

于 2009-09-23T21:37:45.490 回答