带编译与不带编译的exec语句

1 投票
2 回答
1520 浏览
提问于 2025-04-15 11:49

这个周末,我一直在研究Michele Simionato的decorator模块,这个模块可以创建保留函数签名的装饰器。它的核心是一个动态生成的函数,工作原理大概是这样的……

src = """def function(a,b,c) :\n    return _caller_(a,b,c)\n"""
evaldict = {'_caller_' : _caller_}
code = compile(src, '<string>', 'single')
exec code in evaldict
new_func = evaldict[function]

在玩这个代码的过程中,我发现可以完全省略编译这一步,直接用一个:

exec src in evaldict

现在,我相信这个额外的步骤是有原因的,但我还没找到这两种方法之间的区别是什么。是性能问题吗?

既然我在问,能不能用eval来实现类似的功能,也就是定义一个新函数并获取它的引用?我试过,但没能成功……

2 个回答

2

compile() 这个函数可以让你控制生成的代码对象,以及它的名字和来源,而 exec 就没有这么灵活。这样做还有个好处,就是当别人阅读你的代码时,他们能明白这些是不同的步骤,并且在以后需要多次执行同样的代码时(用 compile() 编译一次,再用 exec 多次执行会更快),这样写代码也是为了让下一个阅读你代码的人更容易理解,这对设计选择来说总是有积极的影响。

2

我看到了一些区别。首先,compile在处理语法错误时,比exec要稍微好一些。我猜真正的原因是,compile对换行符的处理非常明确,而exec在这方面就没那么精确。

我很好奇为什么会用compileexec来代替内部函数。我之前不知道compileexec可以让你控制哪些全局变量是可用的。这真有意思。

撰写回答