Python代码对象与字节码
Python代码编译为Code Object后由虚拟机执行,理解这一过程有助于性能优化和代码分析。
Code Object 结构
Python
def example(a, b=10, *args, **kwargs):
"示例函数"
local = a + b
for arg in args:
local += arg
return local
code = example.__code__
# Code Object 属性
print(f"名称: {code.co_name}") # 'example'
print(f"参数数量: {code.co_argcount}") # 2(不含*args, **kwargs)
print(f"位置参数: {code.co_posonlyargcount}") # 0
print(f"关键字参数: {code.co_kwonlyargcount}")# 0
print(f"局部变量: {code.co_varnames}") # ('a', 'b', 'args', 'kwargs', 'local', 'arg')
print(f"自由变量: {code.co_freevars}") # ()(无闭包)
print(f"常量: {code.co_consts}") # (None, 10)
print(f"名称: {code.co_names}") # ()(无全局名)
print(f"文件名: {code.co_filename}")
print(f"首行号: {code.co_firstlineno}") # 函数定义行号
print(f"标志: {code.co_flags}") # 位标志
| 属性 | 说明 |
|---|---|
co_name | 代码块名称 |
co_filename | 源文件路径 |
co_firstlineno | 代码块起始行号 |
co_argcount | 位置参数数量 |
co_varnames | 局部变量名元组 |
co_consts | 常量元组 |
co_names | 全局/属性名元组 |
co_freevars | 自由变量(闭包捕获) |
co_code | 字节码字节串 |
co_lnotab | 行号映射表(旧版) |
co_lines | 行迭代器(Python 3.10+) |
compile 函数
Python
# compile(source, filename, mode, flags=0)
source = "
def greet(name):
return f"Hello, {name}"
print(greet("World"))
"
# mode: 'exec'(模块)、'eval'(表达式)、'single'(单语句)
code_obj = compile(source, '<string>', 'exec')
# 执行编译后的代码
exec(code_obj) # Hello, World
# eval模式:仅表达式
expr_code = compile('2 + 3 * 4', '<expr>', 'eval')
result = eval(expr_code)
print(result) # 14
Python
# 编译标志
import ast
#优化级别
code = compile(source, '<string>', 'exec', flags=0) # 正常
code_opt1 = compile(source, '<string>', 'exec', flags=ast.PyCF_OPTIMIZED_BYTECODE)
# 保留文档字符串(默认会移除)
code = compile(source, '<string>', 'exec', dont_inherit=True)
dis 模块分析字节码
Python
import dis
def simple_add(a, b):
return a + b
# 反汇编
dis.dis(simple_add)
# 2 0 LOAD_FAST 0 (a)
# 2 LOAD_FAST 1 (b)
# 4 BINARY_ADD
# 6 RETURN_VALUE
# 详细信息
dis.show_code(simple_add)
Python
# 分析控制流
def conditional(x):
if x > 0:
return x
return -x
dis.dis(conditional)
# 对比跳跃指令:POP_JUMP_IF_FALSE
Python
# 字节码操作
code = simple_add.__code__
print(f"字节码长度: {len(code.co_code)}")
print(f"字节码内容: {code.co_code}") # b'\x7c\x00\x00\x7c\x01\x00\x17\x53\x00'
Code Object 嵌套
Python
def outer():
def inner():
return "nested"
return inner
outer_code = outer.__code__
print(f"外层常量: {outer_code.co_consts}")
# 包含 inner 函数的 Code Object
inner_code = outer_code.co_consts[1] # 或 outer().__code__
print(f"内层名称: {inner_code.co_name}") # 'inner'
Python
# 类定义的 Code Object
class MyClass:
attr = 123
def method(self):
return self.attr
# 类体执行后创建类对象
class_code = MyClass.__dict__['__init__'].__code__ # 如果有 __init__
# 查看类定义的字节码
import dis
dis.dis(MyClass)
手动创建 Code Object
Python
import types
# 创建简单的 Code Object(高级用法)
def make_simple_code():
"创建返回常量的 Code Object"
return types.CodeType(
co_argcount=0,
co_posonlyargcount=0,
co_kwonlyargcount=0,
co_nlocals=0,
co_stacksize=1,
co_flags=0,
codetype=b'\x64\x00\x00\x53', # LOAD_CONST 0; RETURN_VALUE
co_consts=(42,),
co_names=(),
co_varnames=(),
co_filename='<generated>',
co_name='generated',
co_firstlineno=1,
co_lnotab=b'',
co_freevars=(),
co_cellvars=(),
)
# Python 3.8+ 参数顺序有变化,使用 CodeType.replace 更安全
original_code = simple_add.__code__
new_code = original_code.replace(co_consts=(100, 200))
函数对象重建
Python
import types
def template(a, b):
"模板函数"
pass
# 获取模板的 Code Object
template_code = template.__code__
# 创建新函数
new_func = types.FunctionType(
code=template_code,
globals=globals(),
name='new_func',
argdefs=None, # 默认参数元组
closure=None, # 闭包单元元组
)
# 执行
print(new_func(1, 2)) # 取决于字节码内容
字节码优化分析
Python
import dis
# 常量折叠
def folded():
return 2 * 3 + 4 * 5
dis.dis(folded)
# 编译时已计算为 26:LOAD_CONST 26
# 循环优化
def loop_unroll():
result = 0
for i in range(5):
result += i
return result
dis.dis(loop_unroll)
# 查看循环的字节码:SETUP_LOOP, FOR_ITER, STORE_FAST 等
要点总结
- Code Object存储字节码、常量、变量名、行号等信息
- **
compile()**将源码编译为Code Object,支持exec/eval/single模式 dis模块是分析和理解字节码的主要工具- 嵌套函数的Code Object存储在外层函数的
co_consts中 - **
types.FunctionType**可用Code Object重建函数对象
📝 发现内容有误?点击此处直接编辑