网易首页 > 网易号 > 正文 申请入驻

Python 标准库:dis(字节码反汇编与执行机制分析)

0
分享至

dis 是 Python 标准库中用于分析字节码的模块,可以将编译后的指令转换为便于阅读的形式,帮助观察变量访问、运算、函数调用和控制流程的实现方式。

它适合学习程序执行机制、比较不同写法的编译结果,以及辅助定位异常或分析性能问题。反汇编展示的是解释器层面的指令结构,不能直接代替运行测试和性能测量。

一、导入与常见应用场景

1、导入模块

dis 随 Python 提供,无需额外安装。

import dis

本文以 CPython 为分析对象。字节码属于解释器实现细节,指令名称、参数含义和输出格式可能随解释器版本变化,不应视为 Python 语言固定不变的规则。

2、常见应用场景

• 理解执行机制:观察表达式如何加载数据、执行运算并返回结果。

• 分析控制流程:查看条件分支、循环和短路求值对应的指令。

• 比较代码结构:分析不同写法生成的指令及代码对象信息。

• 观察编译优化:检查常量折叠等优化是否发生。

• 辅助调试:结合异常回溯定位发生错误的指令。

3、与相关模块的分工

• dis:分析编译后的字节码与相关信息。

• ast:分析源代码的语法结构。

• inspect:获取函数、类、参数和源码等对象信息。

• timeit:测量小段代码的执行时间。

• cProfile:分析程序运行过程中各函数的调用与耗时。

dis 主要回答“代码被编译成了什么结构”;执行频率和实际耗时通常需要其他工具测量。

二、核心概念

1、源代码、字节码与机器码

源代码(Source Code)是编写的 Python 文本。

在 CPython 的常规执行流程中,源代码经过解析和编译,形成包含字节码的代码对象,再由解释器执行。

字节码(Bytecode)是供解释器处理的指令表示,不等同于处理器直接执行的机器码(Machine Code)。dis 展示的是字节码层面的反汇编,而不是硬件汇编指令。

2、代码对象

代码对象(Code Object)保存编译后的指令及相关信息,例如常量、变量名称和源码位置。

普通 Python 函数通过 __code__ 属性关联代码对象:

代码对象与函数对象不同。函数还关联全局命名空间、默认参数和闭包等执行所需的信息。

3、指令与操作参数

一条字节码指令通常包含操作码(Opcode),并可能带有操作参数。

操作参数不一定是源代码中的数值,也可能表示常量索引、变量索引、运算类型或跳转信息。

阅读时应结合指令名称与参数解释,不宜单独根据参数数字推断作用。

4、求值栈

CPython 的许多指令通过求值栈(Evaluation Stack)传递中间结果。

例如,计算 a + b 时,可以从概念上理解为:

• 取得 a 和 b 的值。

• 执行加法,将结果作为新的中间值。

• 将结果返回给调用方。

实际输出可能将多个动作组合为一条指令,或采用专门化指令,因此不必强求每个源码动作都对应一条独立指令。

三、使用 dis.dis() 查看字节码

1、反汇编函数

dis.dis() 默认将反汇编结果写入标准输出,函数本身返回 None。

这里传入的是函数对象 add,不会调用该函数。若写成 dis.dis(add(2, 3)),则会先计算函数结果,再尝试对结果进行反汇编,通常不符合分析目的。

2、阅读输出中的信息

反汇编输出主要包含:

• 源码位置:指令对应的行号或更详细的位置。

• 逻辑标签:用于标记跳转目标等位置。

• 指令名称:说明该指令执行的操作。

• 操作参数:指令使用的数字参数。

• 参数解释:变量名、常量值、运算符或跳转目标等可读信息。

当前输出通常使用逻辑标签表示跳转目标。需要同时查看指令偏移量和更详细的源码位置时,可以使用:

偏移量用于定位字节码中的位置,不是源代码行号;源码位置与字节码指令也不一定一一对应。

3、理解常见指令类别

阅读输出时,可以先关注指令的作用类别:

• LOAD_CONST:加载常量。

• LOAD_FAST、LOAD_FAST_BORROW 等:访问局部变量,具体指令具有不同的内部语义。

• STORE_FAST:将值保存到局部变量。

• LOAD_GLOBAL:查找全局名称或内置名称。

• BINARY_OP:执行由参数指定的二元或原地操作。

• COMPARE_OP:执行比较操作。

• CALL:执行调用相关操作。

• RETURN_VALUE:返回栈顶结果。

这些名称只是阅读入口。实际代码还可能使用组合指令或特化指令,应以当前解释器的输出与对应定义为准。

4、分析源代码字符串

dis 会先编译字符串,再展示反汇编结果,不会执行其中的赋值和乘法。因此,分析时不要求 price 和 quantity 已经有值。

也可以显式创建代码对象:

eval 模式用于表达式,exec 模式用于语句序列。选择不同模式,生成的代码结构也可能不同。

5、控制嵌套代码的展开

depth=0 只显示当前代码对象,不递归展开其中的嵌套代码对象。

省略 depth 时,dis 会继续分析嵌套代码对象。这里控制的是反汇编展示的递归深度,不是程序运行时的递归限制。

四、结构化读取指令与代码信息

1、遍历 Instruction 对象

需要在程序中分析指令时,使用 get_instructions() 比解析打印文本更合适。

    

get_instructions() 返回迭代器,每次产生一个指令对象(Instruction)。

常用字段包括:

• offset:指令在字节码中的偏移位置。

• opname:可读的指令名称。

• opcode:操作码数值。

• arg:数字形式的操作参数,没有参数时为 None。

• argval:解析后的参数值。

• argrepr:参数的可读描述。

• is_jump_target:是否为其他指令的跳转目标。

2、查看源码位置

    

位置对象包含起止行号与列偏移。部分位置数据可能为 None,分析程序应考虑信息缺失的情况。

列偏移按源码的 UTF-8 字节偏移表示。源码包含中文等非 ASCII 字符时,不能直接将它当作 Python 字符串的字符索引切片。

3、查看代码对象摘要

结果通常包含函数名称、文件名、参数数量、局部变量数量、栈空间需求、常量和名称等信息。

也可以直接打印:

code_info() 返回字符串,show_code() 直接输出信息。

其中的栈空间信息描述求值栈所需的槽位,不表示函数调用次数、递归深度或内存字节数。

4、使用 Bytecode 对象

    

Bytecode 将常用分析功能组织在一个对象中:

• info():返回代码对象摘要字符串。

• dis():返回反汇编结果字符串。

• 迭代对象:逐项获取 Instruction。

因此,需要将反汇编结果保存到变量时,可使用 Bytecode.dis();不宜将 dis.dis() 的返回值当作结果文本。

五、分析条件、循环与编译优化

1、条件分支

阅读时可以依次寻找:

• score 与常量的加载。

• 比较操作。

• 根据比较结果决定执行路径的跳转。

• 各分支的返回操作。

反汇编列出的是可能执行的指令结构。一次函数调用通常只经过其中一条路径,不会按输出顺序执行所有分支。

2、循环结构

循环中通常可以观察到获取迭代器、取得下一项、更新累计值和返回循环位置等操作。

循环体的指令在反汇编中只出现一份,但运行时可能重复执行很多次。因此,静态指令数量不等于实际执行次数。

3、短路求值

or 会根据第一个操作数的真值决定是否需要取得第二个操作数。

该表达式返回某个操作数本身,不会统一转换为 True 或 False。可以结合跳转和返回位置观察这种选择行为。

4、常量折叠

在常见 CPython 编译结果中,纯常量表达式 2 + 3 * 4 会提前计算为 14;第二个函数中的 3 * 4 也可能提前合并为 12,而 value 相关的加法仍需要运行时执行。

这种编译期处理称为常量折叠(Constant Folding)。

它说明源代码中的每个运算符不一定对应一次运行时运算。具体优化范围由编译器决定,不能据此认为所有看似固定的表达式都会被提前计算。

六、运行时特化与内联缓存

1、观察运行后的指令形式

CPython 可以根据运行时情况,对部分操作采用更有针对性的执行形式,这类机制称为特化(Specialization)。

adaptive=True 用于显示可能经过运行时特化的字节码。

重复调用使解释器有机会观察操作数类型等信息,但不保证一定出现某种指令。特化结果受解释器实现、构建配置、调用历史和输入类型影响。

2、查看内联缓存

内联缓存(Inline Cache)用于保存解释器执行某些操作时可复用的信息,通常与前面的指令关联。

show_caches=True 会显示这些缓存条目。它们不是源代码中的独立语句,也不能简单按普通业务操作累计。

当前的 get_instructions() 不再将缓存条目作为独立 Instruction 返回;相关信息可通过指令对象的 cache_info 字段读取。不要将它与 dis.dis() 的缓存显示方式混为一谈。

3、分析结果的边界

默认反汇编与特化视图展示的层次不同。比较两段代码时,应明确是否启用了 adaptive 和缓存显示。

dis 不会提供完整的处理器机器码视图;运行时优化也可能超出普通字节码输出能够直接呈现的范围。

七、异常定位与命令行使用

1、根据异常回溯定位指令

    

Bytecode.from_traceback() 根据回溯创建分析对象,并标记引发异常的指令位置。

本例可将错误与除法操作联系起来。它提供的是指令位置,具体原因仍需要结合异常类型、输入数据和调用上下文判断。

2、在终端反汇编文件

将需要分析的代码保存为 example.py,然后运行:

该命令读取并编译源文件,输出反汇编结果,不会执行文件中的顶层业务代码。

常用选项包括:

• -C:显示内联缓存。

• -O:显示指令偏移量。

• -P:显示更详细的源码位置。

例如:

这里的 -O 位于 -m dis 之后,是 dis 的显示选项;python -O -m dis example.py 中的 -O 则是解释器的优化选项,两者作用不同。

3、保存反汇编结果

    

也可以将 dis.Bytecode(square).dis() 返回的字符串写入文件,便于归档或比较。

八、应用举例:比较两种列表构造方式

以下示例比较普通循环和列表推导式的编译结构,并将代码摘要、反汇编结果和指令名称统计保存为报告。

报告保存在 bytecode_report.txt,再次运行会覆盖同名文件。

阅读报告时,可以关注普通循环中的方法访问与调用,以及列表推导式中可能出现的 LIST_APPEND 等操作,理解两种写法的编译结构。

示例只统计各函数当前代码对象中的指令,不递归累计嵌套代码对象;运行时执行次数也不包含在该统计中。

如果需要比较耗时,可以在上述函数定义之后补充:

    

这些时间还包含函数调用及计时包装的开销,应在相同环境和相同输入下比较,并结合实际业务规模判断。

指令更少不一定意味着执行更快。一个调用指令可能触发大量底层工作,而数据类型、缓存状态和内存分配也会影响耗时。

九、常用函数与类速览

以下列出常用调用形式,省略部分可选参数。

• dis.dis(x):输出反汇编结果,返回 None。

• dis.dis(x, file=file):将反汇编结果写入指定文本流。

• dis.dis(x, depth=0):只分析当前层级,不递归展开嵌套代码对象。

• dis.dis(x, show_offsets=True):显示指令偏移量。

• dis.dis(x, show_positions=True):显示更详细的源码位置。

• dis.dis(x, adaptive=True):显示可能经过运行时特化的字节码。

• dis.dis(x, show_caches=True):显示内联缓存。

• dis.get_instructions(x):返回 Instruction 对象的迭代器。

• dis.code_info(x):返回代码对象摘要字符串。

• dis.show_code(x):直接输出代码对象摘要。

• dis.Bytecode(x):创建可迭代的字节码分析对象。

• Bytecode.dis():返回格式化的反汇编字符串。

• Bytecode.info():返回代码对象摘要字符串。

• dis.Bytecode.from_traceback(tb):根据异常回溯创建分析对象并标记相关指令。

• dis.stack_effect(opcode, oparg=None, *, jump=None):计算指令对求值栈深度的净影响。

十、补充说明

1、字节码与语言语义

Python 语言规定表达式和语句的行为,CPython 字节码描述某种具体实现。

学习时应先理解代码语义,再用反汇编观察实现,不宜将特定指令组合当作编写 Python 程序必须遵守的固定模式。

2、结构分析与性能判断

dis 展示指令结构,不记录每条指令实际执行了多少次,也不直接测量耗时。

发现可疑结构后,应结合 timeit、cProfile 或实际任务测试验证,再决定是否优化。

3、编译分析与代码执行

反汇编普通函数对象或编译源代码字符串,不会调用被分析的函数或执行业务语句。

但为了取得函数而导入模块时,模块顶层代码仍可能执行;特化示例中的重复调用和性能测量也会实际运行目标函数。

4、反汇编与源码恢复

dis 不能完整恢复原始源码。变量名和部分位置信息可能保留,但注释、排版以及某些源码结构已经在编译过程中丢失或改变。

因此,反汇编结果适合分析执行结构,不能替代源码备份或作为完整的反编译结果。

5、栈变化与执行成本

stack_effect() 返回的是某条指令对求值栈深度的净影响,不是执行时间或内存消耗。

对于存在跳转的指令,跳转与不跳转时的栈变化可能不同。计算整个函数的栈行为时,需要结合控制流程,不能简单将所有指令的结果相加。

小结

dis 将 CPython 字节码转换为可读指令,帮助理解变量访问、控制流程、编译优化和运行时特化。分析时应结合源码语义与解释器环境;涉及性能结论,还需通过计时或性能分析工具验证。


“点赞有美意,赞赏是鼓励”

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
法国访谈节目《The Bridge》就姆巴佩事件道歉:视频系今年4月录制的节目花絮;我们对该视频给中国及世界各地的人们造成的冒犯深表遗憾

法国访谈节目《The Bridge》就姆巴佩事件道歉:视频系今年4月录制的节目花絮;我们对该视频给中国及世界各地的人们造成的冒犯深表遗憾

都市快报橙柿互动
2026-10-28 06:55:44
樱花演唱会再露"下乳"引争议,粉丝怒问造型团队

樱花演唱会再露"下乳"引争议,粉丝怒问造型团队

浅遇时光
2026-10-26 04:35:36
3-0,3-0,WTT冠军赛乱套了:孙颖莎制造惨案,林诗栋超级大逆转!

3-0,3-0,WTT冠军赛乱套了:孙颖莎制造惨案,林诗栋超级大逆转!

田先生篮球
2026-10-28 06:48:35
老戏骨董勇车险续保被卡一个月,网上维权,吐槽太平洋保险“店大欺客”

老戏骨董勇车险续保被卡一个月,网上维权,吐槽太平洋保险“店大欺客”

大风新闻
2026-10-28 18:21:02
某界汽车,月销量仅剩29辆!

某界汽车,月销量仅剩29辆!

电动内参
2026-10-29 01:32:33
名记:皇马内部不理解姆巴佩发声明为何不通过俱乐部,俱乐部认为处理类似事情更有经验

名记:皇马内部不理解姆巴佩发声明为何不通过俱乐部,俱乐部认为处理类似事情更有经验

尘语者
2026-10-28 17:07:59
皇马官方声明道歉:对中国人民充满尊重,姆巴佩已表达悔意

皇马官方声明道歉:对中国人民充满尊重,姆巴佩已表达悔意

全景体育V
2026-10-28 17:11:47
《伟大的长征》钱壮飞掉队那一段,越想越不对:一个拆过六封绝密电报的人,最后居然被一匹骡子要了命

《伟大的长征》钱壮飞掉队那一段,越想越不对:一个拆过六封绝密电报的人,最后居然被一匹骡子要了命

磊子讲史
2026-10-28 14:55:52
改革开放后有三大耻辱,件件都是民族伤疤。1993年、1999年、2001年这三个年份对中国人而言,每个数字背后都是一段屈辱经历

改革开放后有三大耻辱,件件都是民族伤疤。1993年、1999年、2001年这三个年份对中国人而言,每个数字背后都是一段屈辱经历

扶苏聊历史
2026-10-28 15:05:54
刚刚,皇马全平台致歉!包含海外超3亿粉丝的多个官方账号

刚刚,皇马全平台致歉!包含海外超3亿粉丝的多个官方账号

十点街球体育
2026-10-28 21:01:39
上市后首份财报出炉!宇树科技前三季度实现净利约3.87亿元,同比增长270.54%

上市后首份财报出炉!宇树科技前三季度实现净利约3.87亿元,同比增长270.54%

北京商报
2026-10-28 19:45:08
队报:皇马拒绝了西甲对姆巴佩事件的帮助;皇马高层想看特瓦斯笑话

队报:皇马拒绝了西甲对姆巴佩事件的帮助;皇马高层想看特瓦斯笑话

懂球帝
2026-10-28 08:58:05
连续数月多次触摸女同事大腿,甚至将手伸入其上衣抚摸隐私部位,42岁摄影师被澳门警方拘捕

连续数月多次触摸女同事大腿,甚至将手伸入其上衣抚摸隐私部位,42岁摄影师被澳门警方拘捕

南方都市报
2026-10-28 08:28:04
76岁加拿大华侨坦言:如今中国生活水平,相当于加拿大80年代?

76岁加拿大华侨坦言:如今中国生活水平,相当于加拿大80年代?

爱下厨的阿酾
2026-10-28 18:59:19
令人心碎!“只有几分钟就走了”,长沙35岁教师骤然离世,满墙荣誉,一双年幼儿女

令人心碎!“只有几分钟就走了”,长沙35岁教师骤然离世,满墙荣誉,一双年幼儿女

火山詩话
2026-10-28 11:12:15
李家超深切哀悼国务院原副总理刘延东逝世

李家超深切哀悼国务院原副总理刘延东逝世

看看新闻Knews
2026-10-28 22:43:14
哈尔滨29岁女子外出游玩被蜱虫咬伤,在ICU住了28天,目前四肢瘫痪,丈夫称已花费40万元治疗

哈尔滨29岁女子外出游玩被蜱虫咬伤,在ICU住了28天,目前四肢瘫痪,丈夫称已花费40万元治疗

新京报
2026-10-28 14:36:32
有钱人的想法是摸不透的,你看71岁的周润发,花1.28亿港元买下山顶豪宅,装修好了却一直没住,也没租给别人。

有钱人的想法是摸不透的,你看71岁的周润发,花1.28亿港元买下山顶豪宅,装修好了却一直没住,也没租给别人。

平凡日子生微光
2026-10-26 15:18:30
旭日旗事件越闹越大!陈宇昕三代都是亲日分子,母亲身份已澄清

旭日旗事件越闹越大!陈宇昕三代都是亲日分子,母亲身份已澄清

平老师666
2026-10-27 20:56:19
黄仁勋彻底不装了!中国不买美国英伟达的H200芯片,全球人工智能芯片市场出现了值得关注的变化,国产份额往上顶,对比很扎眼!

黄仁勋彻底不装了!中国不买美国英伟达的H200芯片,全球人工智能芯片市场出现了值得关注的变化,国产份额往上顶,对比很扎眼!

林杰论事
2026-10-28 18:03:38
2026-10-29 02:59:00
MediaTea
MediaTea
专业的数字媒体、新媒体技术
2258文章数 85关注度
往期回顾 全部

科技要闻

宇树科技前三季净利暴增270%

头条要闻

仅退款后冰柜仍插着电在使用 买家回应

头条要闻

仅退款后冰柜仍插着电在使用 买家回应

体育要闻

0胜4负与篮网国王一桌 热火字母哥赌错了?

娱乐要闻

巾帼不让须眉!章子怡拿下重磅荣誉

财经要闻

iPhone Duo七年等来一场吐槽大会

汽车要闻

首销期权益价23.98万起 2026款理想i6上市

态度原创

教育
家居
游戏
手机
健康

教育要闻

一场错位的需求拉锯!“没钱,干陪有什么用?”初中女生的话戳破无数全职妈妈的幻想!

家居要闻

2026建博会(广州) 公装联探展交流活动

盖世小鸡推出《GTA6》配色手柄 但疑似没有联动

手机要闻

华为Pura90 Plus、畅享100系列发布!多款新品亮相

查不出猝死风险?可能是项目没做对

无障碍浏览 进入关怀版