Python compile 函数
上次修改时间:2025 年 4 月 11 日
这份全面的指南探讨了 Python 的 compile
函数,该函数将源代码转换为字节码或 AST 对象。我们将介绍语法模式、代码对象以及动态代码编译的实践示例。
基本定义
compile
函数将源代码转换为可以被 eval
或 exec
执行的代码或 AST 对象。它支持三种模式:exec
、eval
和 single
。
关键参数:source(字符串/字节/AST)、filename(用于错误消息)、mode(exec/eval/single)、flags(优化)、dont_inherit(编译器选项)。返回一个准备好执行的代码对象。
基本编译示例
此示例演示了如何使用 compile
函数的不同模式编译一个简单的表达式和语句。
# Compile an expression for eval code_obj = compile('3 + 4 * 2', '<string>', 'eval') print(eval(code_obj)) # 11 # Compile a statement for exec code_obj = compile('x = 5\ny = 10\nprint(x + y)', '<string>', 'exec') exec(code_obj) # 15 # Compile for single mode (interactive) code_obj = compile('print("Hello")', '<string>', 'single') exec(code_obj) # Hello
第一个示例编译一个用于 eval
的表达式,它期望一个单一的表达式。第二个示例编译多个用于 exec
的语句。
single
模式用于交互式使用 - 它像 Python REPL 一样打印表达式结果。请注意每种模式的不同返回行为。
从文件编译
此示例演示了从文件编译 Python 代码,这对于实现自定义解释器或预处理代码非常有用。
# Assume test.py contains: print("Hello from file") with open('test.py', 'r') as f: source = f.read() code_obj = compile(source, 'test.py', 'exec') exec(code_obj) # Hello from file # Inspect the code object print(f"Co_code: {code_obj.co_code[:20]}...") # First 20 bytes print(f"Co_names: {code_obj.co_names}") # Used names
在这里,我们从文件读取 Python 代码并编译它。 filename 参数有助于显示错误消息。然后,我们执行已编译的代码对象。
该示例还显示了检查代码对象的属性,例如 co_code
(字节码)和 co_names
(使用的变量名)。这些对于内省非常有用。
AST 编译
这个高级示例演示了从抽象语法树 (AST) 编译,从而实现强大的代码生成和转换功能。
import ast # Create AST for: print("Hello AST") tree = ast.Module( body=[ast.Expr( value=ast.Call( func=ast.Name(id='print', ctx=ast.Load()), args=[ast.Constant(value='Hello AST')], keywords=[] ) )], type_ignores=[] ) # Compile and execute AST code_obj = compile(tree, '<ast>', 'exec') exec(code_obj) # Hello AST # Convert AST back to source print(ast.unparse(tree)) # print('Hello AST')
我们手动构造一个表示 print 语句的 AST,然后编译并执行它。这演示了 Python 的完整编译管道。
ast.unparse
将 AST 转换回源代码,显示了往返转换能力。 AST 操作实现了强大的元编程。
错误处理
此示例显示了编译无效代码时如何正确处理错误,包括语法错误和编译警告。
# Syntax error try: compile('print("Hello)', '<string>', 'exec') # Missing quote except SyntaxError as e: print(f"SyntaxError: {e}") # TypeError for wrong mode try: compile('x = 5', '<string>', 'eval') # 'eval' needs expression except SyntaxError as e: print(f"SyntaxError: {e}") # Warning example import warnings warnings.simplefilter('always') compile('from __future__ import braces', '<string>', 'exec')
第一个案例显示了处理语法错误(未关闭的字符串)。第二个案例演示了模式不匹配错误(在 eval 模式下赋值)。
最后一个示例触发了针对无效未来导入的 SyntaxWarning
。可以通过 warnings 模块控制警告。
优化标志
此示例演示了使用编译标志来控制优化和未来功能行为。
from __future__ import annotations import ast # With optimizations (constant folding) code_obj = compile('3 + 4 * 2', '<string>', 'eval', flags=ast.PyCF_ONLY_AST, optimize=2) print(ast.dump(code_obj, indent=2)) # Shows optimized AST # Without optimizations code_obj = compile('3 + 4 * 2', '<string>', 'eval', optimize=0) print(eval(code_obj)) # 11 # With future features code_obj = compile('def foo(x: int) -> None: pass', '<string>', 'exec', flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT)
第一部分显示了使用优化标志生成 AST。第二部分比较了优化和未优化的编译。第三部分演示了未来功能。
优化级别 2 执行常量折叠。未来标志启用了诸如顶级 await 之类的功能。 这些标志提供了细粒度的编译控制。
最佳实践
- 安全: 切勿在没有沙盒的情况下编译不受信任的输入
- 模式选择: 选择正确的模式 (exec/eval/single)
- 错误处理: 始终处理 SyntaxError 和 TypeError
- AST 操作: 优先选择 AST 而不是字符串操作
- 优化: 使用适当的优化级别
资料来源
作者
列出所有 Python 教程。