如何批量从多个.py文件中提取Python字节码并解决dis输出捕获问题
Python批量提取.py文件字节码解决方案
方法说明
你不需要手动把.py文件的代码包裹到def中,直接编译源码或者动态导入模块,就能提取到文件内所有定义的函数、类方法甚至顶层代码的字节码。核心思路是:
- 遍历目标目录下所有.py文件
- 直接编译每个py文件得到模块级代码对象
- 递归遍历代码对象的
co_consts属性,提取所有函数/类的代码对象 - 用
dis.dis()输出字节码到指定文件
你现有代码的错误点
py_compile.main()传入的是不带路径的文件名,无法定位到源文件,需要传入完整的文件绝对路径- 遍历pyc文件时
glob.glob('*.pyc')默认读取当前工作目录的pyc,你的pyc存放在__pycache__目录下,路径不匹配 - 打开pyc文件用了
r文本模式,pyc是二进制文件,必须用rb模式打开 - 变量名混乱:代码中出现未定义的
f3、file变量,上下文没有声明 - 写入文件逻辑错误:不能直接把
StringIO对象写入文件,需要调用out.getvalue()获取字节码字符串再写入 - 加载marshal后得到的是整个模块的代码对象,如果要单独提取每个函数的字节码,还需要遍历模块代码对象的常量区,筛选出类型为代码对象的内容
完整可用实现代码
import os import dis import marshal import py_compile from io import StringIO # 配置路径 SOURCE_PATH = r'C:/mydirectorycomeshere/SourceCodeChecker/' OUTPUT_PATH = r'C:/mydirectorycomeshere/bytecode_output/' os.makedirs(OUTPUT_PATH, exist_ok=True) # 适配不同Python版本的pyc头长度 header_size = 8 if tuple(map(int, os.sys.version.split('.')[:2])) >= (3,6): header_size = 12 if tuple(map(int, os.sys.version.split('.')[:2])) >= (3,7): header_size = 16 def get_all_code_objs(code_obj, result=None): """递归提取所有代码对象(包括模块、函数、嵌套函数)""" if result is None: result = [] result.append(code_obj) for const in code_obj.co_consts: if type(const).__name__ == 'code': get_all_code_objs(const, result) return result # 第一步:编译所有py文件为pyc py_files = [] for root, _, files in os.walk(SOURCE_PATH): for f in files: if f.endswith('.py'): full_path = os.path.join(root, f) py_files.append(full_path) py_compile.compile(full_path) # 第二步:读取pyc文件提取字节码 for py_path in py_files: # 生成对应pyc的路径,适配Python3.2+的pyc命名规则 py_name = os.path.basename(py_path).rsplit('.',1)[0] pyc_name = f"{py_name}.cpython-{os.sys.version_info.major}{os.sys.version_info.minor}.pyc" pyc_path = os.path.join(os.path.dirname(py_path), '__pycache__', pyc_name) if not os.path.exists(pyc_path): continue # 读取pyc提取代码对象 with open(pyc_path, 'rb') as f: f.seek(header_size) module_code = marshal.load(f) # 提取所有代码对象生成字节码 all_codes = get_all_code_objs(module_code) output_content = [] for idx, code in enumerate(all_codes): out = StringIO() dis.dis(code, file=out) code_name = code.co_name if code.co_name != '<module>' else '顶层代码' output_content.append(f"===== 代码块{idx}: {code_name} =====\n{out.getvalue()}\n") # 保存到输出文件 output_file = os.path.join(OUTPUT_PATH, f"{py_name}_bytecode.txt") with open(output_file, 'w', encoding='utf-8') as f: f.write('\n'.join(output_content)) print("所有字节码已生成完成")
内容的提问来源于stack exchange,提问作者Llyx
相关产品推荐
相关产品推荐

