如何使用AST将文本编译为函数?

时间:2012-11-12 19:13:41

标签: python exec abstract-syntax-tree

我需要将输入字符串(来自数据库)编译为函数并运行它。这是我目前使用的方法:

说我已经定义了这个功能:

def foo():
    print "Yo foo! I am a function!"

我从数据库中读到的字符串说我应该调用这个函数:

string_from_db = "foo()"

然后我形成一个函数(我可以控制其名称),它返回我从数据库中读入的函数:

my_func_string = "def doTheFunc():\n\t return " + string_from_db

现在我编译字符串,并将其设置为稍后用于处理的函数名称:

exec my_func_string
processor = doTheFunc

我可以稍后通过运行processor()来调用它:Yo foo! I am a function!

我的问题:在这段代码之上有一条评论(由一位长期失去的开发者留下):

    ###############################################################
    # The following method for getting a function out of the text #
    # in the database could potentially be replaced by using      #
    # Python's ast module to obtain an abstract syntax tree and   #
    # put it inside of a function node                            #
    ###############################################################

我想更多地了解这种“潜在替代品”。我已经看了AST,但是我对它如何帮助我做上面的代码所做的事情感到非常困惑。

  1. 如何使用AST完成同样的事情?或者AST在这个过程中可以帮助我吗?
  2. 使用AST的实现更好,为什么?

1 个答案:

答案 0 :(得分:5)

在评估不受信任的代码时,AST是一个更安全的选择,可能包含恶意指令,evalexec可以执行任何表达式,而另一方面,AST允许您解析和验证表达自己,或使用ast.literal_eval执行有限的表达式,有点像沙盒,它只允许字符串,列表,数字和其他一些东西。这只是一个简单的例子:

import ast
a = ast.literal_eval("[1,2,3,4]") //evaluate an expression safely.

将字符串解析为AST的另一个示例:

import ast
source = '2 + 2'
node = ast.parse(source, mode='eval')
ast.dump(node)

打印:

Expression(body=BinOp(left=Num(n=2), op=Add(), right=Num(n=2)))

有一个非常好的教程here以及documentation