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

5
我需要将一个来自数据库的输入字符串编译为函数并运行它。这是我目前使用的方法:
假设我已经定义了这个函数:
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!我是一个函数!” 我的问题:在这段代码上方有一个注释(由一个失踪的开发人员留下):
    ###############################################################
    # 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实现是否更好,为什么?

6
你所在的领域是黑暗魔法。 - Jakob Bowyer
1
如果您知道字符串是安全的,则没有理由使用 ast 而不是 exec()。Python 解释器已经实现了将 Python 源代码解析为函数对象,为什么要复制它呢? - millimoose
@millimoose,我最终选择了exec实现,因为我知道我的字符串是安全的。然而,这个问题让我对ast的更好用法有了更深刻的认识。谢谢! - dinkelk
1个回答

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)))

这里有一篇非常好的教程(链接),还有文档

。这些教程和文档都和Python语言内部的抽象语法树有关,对于IT技术人员来说非常有用。

很棒的教程!我该如何“验证表达式”?我怎样才能知道代码是否糟糕或不符合我的要求?假设我需要编译小函数;我不能仅限于简单的字符串、列表等。 - dinkelk
@babydanks 你可以查找它是否调用了不应该调用的任何函数,比如 open - iabdalkader
啊!在什么级别上最容易做到这一点?一旦您拥有AST函数节点?(即,检查“open”的最简单方法是什么?) - dinkelk
@babydanks 你应该看一下 NodeVisitor类,教程里也有一个例子。 - iabdalkader
@babydanks,关键是它比evalexec更能让你控制哪些内容需要执行,哪些不需要。 - iabdalkader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接