程序员文章、书籍推荐和程序员创业信息与资源分享平台

网站首页 > 技术文章 正文

python散装笔记——106: 使用 exec 和 eval 动态执行代码

hfteth 2025-03-05 16:19:23 技术文章 14 ℃


Argument

Details

expression

表达式代码字符串或 code 对象

object

语句代码字符串或 code 对象

globals

用于全局变量的 dictionary。如果未指定 locals,该字典也将用于 locals。如果省略,则使用调用作用域的 globals()

locals

用于局部变量的映射对象。如果省略,则使用为 globals 传递的映射对象。如果两者都省略,则调用作用域的 globals()locals() 将分别用于 globalslocals

1: 使用 exec、eval 或 ast.literal_eval 执行未受信任用户提供的代码

无法使用 evalexec 安全地执行来自不信任用户的代码。即使是 ast.literal_eval 也容易导致解析器崩溃。有时可以防范恶意代码的执行,但并不排除解析器或标记符号生成器彻底崩溃的可能性。

要对不信任的用户执行的代码进行评估,您需要使用一些第三方模块,或者用 Python 编写自己的解析器和虚拟机。

2: 使用 ast.literal_eval 评估包含 Python 字面量的字符串

如果字符串中包含 Python 字面量,如字符串、浮点数等,可以使用 ast.literal_eval 代替 eval 来求值。这样做的另一个好处是只允许使用特定的语法。

>>> import ast
>>> code = """(1, 2, {'foo': 'bar'})"""
>>> object = ast.literal_eval(code)
>>> object
(1, 2, {'foo': 'bar'})
>>> type(object)

然而,这对执行不信任用户提供的代码并不安全,而且使用精心制作的输入使解释器崩溃也是轻而易举的事

>>> import ast
>>> ast.literal_eval('()' * 1000000)
[5] 21358 segmentation fault (core dumped) python3

这里的输入是一个重复了一百万次的 () 字符串,这会导致 CPython 解析器崩溃。CPython 开发人员不会将解析器中的错误视为安全问题。

3: 使用执行程序评估语句

>>> code = """for i in range(5):\n print('Hello world!')"""
>>> exec(code)
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!

4: 使用 eval 计算表达式

>>> expression = '5 + 3 * a'
>>> a = 5
>>> result = eval(expression)
>>> result
20

5: 预编译表达式以对其进行多次评估

内置函数 compile 可用于将表达式预编译为代码对象,然后将代码对象传递给 eval。这将加快重复执行已求值代码的速度。编译 “的第三个参数必须是字符串”eval"。

>>> code = compile('a * b + c', '', 'eval')
>>> code
<code object  at 0x7f0e51a58830, file "", line 1>
>>> a, b, c = 1, 2, 3
>>> eval(code)
5

6: 使用自定义全局项用 eval 评估表达式

>>> variables = {'a': 6, 'b': 7}
>>> result = eval('a * b', variables)
>>> print(result)
42

此外,这样代码就不会意外地引用外部定义的名称:

>>> eval('variables')
{'a': 6, 'b': 7}
>>> eval('variables', globals=variables)
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 1, in 
NameError: name 'variables' is not defined

例如,使用 defaultdict 可以将未定义的变量设置为零:

>>> from collections import defaultdict
>>> variables = defaultdict(int, {'a': 42})
>>> eval('a * c', globals=variables) # note that 'c' is not explicitly defined
0

最近发表
标签列表