Skip to content

Latest commit

 

History

History
103 lines (48 loc) · 2.11 KB

动态编译.md

File metadata and controls

103 lines (48 loc) · 2.11 KB

动态编译

动态编译指的是在运行时接收字符串,动态的将其编译为python可执行的代码的功能.

python提供了两个函数用于实现动态编译:

execeval函数

  • eval(exp[, globals[, locals]])

    • globals是字典形式,表示全局命名空间,如果传入globals的字典中缺少__builtins__ 的时候,当前的全局命名空间将作为globals参数输入并在表达式计算之前被解析.
    • locals则为任何映射对象,表示局部命名空间,与globals两者默认相同.

    如果两者都省略则表示在eval的调用环境中执行

  • exec()

    eval()类似的是exec()方法,但exec是翻译并执行.exec常与文件读取操作结合使用,直接传递python的代码文件运行

a = eval("lambda *x: sum(x)")
a(1,2,3,4,5)
15
%timeit a(1,2,3,4,5,6,7,8,9)
258 ns ± 2.81 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit lambda *x:sum(x)(1,2,3,4,5,6,7,8,9)
58 ns ± 0.763 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
exec("aa = lambda x: x")
aa(10)
10

evalexec有两个弊端:

  • 降低运算效率

    如上面看到的,运行时间上差距不小

  • 安全性

    这主要是因为可以调用一些危险的方法而没有设限.也就是所谓的代码注入攻击.

当然了,我们也可以通过限制globalslocals来实现对可用项的限制.

如果只是为了传入参数,那么可以使用ast库的literal_eval函数,它是安全的

import ast
ast.literal_eval("[1,2,3]")
[1, 2, 3]

在Python中做元编程时,最好不用execeval 函数.如果接收的字符串(或片段)来自不可信的源,那么这两个函数会带来严重的安全风险.Python提供了充足的内省工具,大多数时候都不需要使用execeval函数.然而,Python核心开发者实现namedtuple函数时选择了使用exec函数,这样做是为了让生成的类代码能通过._source获取.