Python中exec/eval/compile区别

一句话总结

函数 能做什么 返回值
eval() 求值单个表达式 表达式的计算结果
exec() 执行任意语句块 None
compile() 将源码编译为字节码对象 字节码对象(code object)

1. eval() — 表达式求值

只能接受表达式,不能接受语句(如 iffor赋值 等)。

1
2
3
4
5
6
7
8
>>> eval("1 + 2")
3

>>> eval("len('hello')")
5

>>> eval("x = 1") # ❌ SyntaxError,赋值是语句不是表达式
SyntaxError: invalid syntax

2. exec() — 执行代码块

可以执行任何 Python 语句:函数定义、类定义、循环、条件、赋值等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> exec("print('hello')")
hello

>>> code = """
... def foo():
... return 42
...
... foo()
... """
>>> exec(code)
42

>>> exec("x = 1 + 2")
>>> x
3

返回值始终是 None


3. compile() — 编译源码

把字符串源码编译成字节码对象(code object),可以延迟执行或反复执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> # expr 模式:编译表达式
>>> c = compile("1 + 2", "<string>", "eval")
>>> eval(c)
3

>>> # exec 模式:编译语句块
>>> c = compile("x = 1", "<string>", "exec")
>>> exec(c)

>>> # single 模式:交互式单条语句
>>> c = compile("print('hi')", "<string>", "single")
>>> exec(c)
hi

三种模式:

模式 适用场景 配合
"eval" 单个表达式 eval()
"exec" 语句块 exec()
"single" 交互式单条语句 exec()

三者关系图

源码字符串 ──compile()──▶ 字节码对象 ──eval()/exec()──▶ 执行结果
  • compile()编译阶段,把字符串变成可执行的字节码
  • eval() / exec()执行阶段,运行字节码或源码
1
2
3
4
5
6
# 等价写法对比
eval("1 + 2") # 直接执行字符串
eval(compile("1 + 2", "<s>", "eval")) # 先编译再执行

exec("x = 1") # 直接执行字符串
exec(compile("x = 1", "<s>", "exec")) # 先编译再执行

实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
# 场景1:动态执行用户输入(需谨慎!)
user_code = input("请输入Python代码: ")
exec(user_code)

# 场景2:缓存编译结果,重复执行更高效
code_obj = compile(open("script.py").read(), "script.py", "exec")
for _ in range(1000):
exec(code_obj) # 避免重复编译

# 场景3:沙箱环境只允许表达式
safe_expr = eval(compile("2 ** 10", "<sandbox>", "eval"),
{"__builtins__": {}}, {})
# 结果: 1024

⚠️ 安全警告

三者都能执行任意代码,不要对不可信的输入使用它们

1
2
# 危险!
eval("__import__('os').system('rm -rf /')")

如需安全求值,考虑用 ast.literal_eval() 替代 eval(),它只支持字面量解析。