python源码分析笔记(8)

python:dis --- Python 字节码反汇编器 阅读详情

1.Python程序的执行过程

实际上Python和java,C#执行原理都可以用两个词概括,------虚拟机,字节码

Python有一个非常核心的东西,这个东西被称为解释器。当我运行一个程序时,例如 python my-program.py ,Python解释器立即被激活,然后开始执行,在运行之前,还要完成一个复制的工作,编译py.文件,结果主要产生一组Python的byte-code(字节码),然后将编译结果交给Python的虚拟机。

 

[demo.py]
class A:
    pass


def fun():
    pass

a = A()
fun()

当我们在执行demo.py时,编译结果会产生PyCodeObject对象和pyc文件。在程序运行期间,编译结果存在于内存的PyCodeObject对象中,而Python结束运行后,编译结果又被保存到了pyc文件,当下一次运行相同的程序时,Python会根据pyc文件中记录的编译结果直接建立内存中的PyCodeObject对象,而不用再次编译。

python中PyCodeObject的声明:

对于代码中的一个Code Block,会创建一个PyCodeObject对象与这段代码对应,对应上文的demo.py,编译完成后总共会创建三个PyCodeObject对象,一个对应demo.py整个文件的,一个是对应class A所代表的Code Block,而最后一个对应def Fun所代表的Code Block.

2.pyc文件

每一个PyCodeObject对象中包含了每一个Code Block中Python源代码经过编译后得到的byte code序列。而前面提到,Python会将这些字节码序列和PyCodeObject对象一起存储在pyc文件。但是我们在命令行敲下python demo.py时并没有生成pyc文件,原因是有写程序可能执行一次就再也不执行了,没必要生成其对应的pyc文件。但是假如碰到import demo的动态加载动作之后,python就会产生pyc文件了。意味着如果Python碰到import demo语句,会首先到设定好的PATH中寻找abc.pyc。如果没有,只发现了demo.py,那么就会编译成PyCodeObject对应的中间结果,然后创建pyc文件,接下来Python才会对abc.pyc进行import动作。

其实pyc是一个二进制文件,那么python如何解释这一堆看上去毫无意义的字节流就至关重要了。要了解pyc文件的格式,首先必须要清楚PyCodeObject中每一个域都表示什么含义。

3.Python的字节码

关于Python的编译结果,我们还剩下最后一个话题了,那就是Python的字节码,这里只会做一个简单的介绍,我们知道Python源代码在执行前会被编译成Python的字节码指令序列,Python虚拟机就是根据这些字节码进行一系列的操作。在Python安装目录的Include文件夹中,opcode.h保存了这些字节码序列

#define STOP_CODE   0
#define POP_TOP     1
#define ROT_TWO     2
#define ROT_THREE   3
#define DUP_TOP     4
#define ROT_FOUR    5
#define NOP     9

#define UNARY_POSITIVE  10
#define UNARY_NEGATIVE  11
#define UNARY_NOT   12
#define UNARY_CONVERT   13

#define UNARY_INVERT    15

#define LIST_APPEND 18
#define BINARY_POWER    19

#define BINARY_MULTIPLY 20
#define BINARY_DIVIDE   21
#define BINARY_MODULO   22
#define BINARY_ADD  23
#define BINARY_SUBTRACT 24
#define BINARY_SUBSCR   25
#define BINARY_FLOOR_DIVIDE 26
#define BINARY_TRUE_DIVIDE 27
#define INPLACE_FLOOR_DIVIDE 28
#define INPLACE_TRUE_DIVIDE 29

#define SLICE       30
/* Also uses 31-33 */

#define STORE_SLICE 40
/* Also uses 41-43 */

#define DELETE_SLICE    50
/* Also uses 51-53 */

#define STORE_MAP   54
#define INPLACE_ADD 55
#define INPLACE_SUBTRACT    56
#define INPLACE_MULTIPLY    57
#define INPLACE_DIVIDE  58
#define INPLACE_MODULO  59
#define STORE_SUBSCR    60
#define DELETE_SUBSCR   61

#define BINARY_LSHIFT   62
#define BINARY_RSHIFT   63
#define BINARY_AND  64
#define BINARY_XOR  65
#define BINARY_OR   66
#define INPLACE_POWER   67
#define GET_ITER    68

#define PRINT_EXPR  70
#define PRINT_ITEM  71
#define PRINT_NEWLINE   72
#define PRINT_ITEM_TO   73
#define PRINT_NEWLINE_TO 74
#define INPLACE_LSHIFT  75
#define INPLACE_RSHIFT  76
#define INPLACE_AND 77
#define INPLACE_XOR 78
#define INPLACE_OR  79
#define BREAK_LOOP  80
#define WITH_CLEANUP    81
#define LOAD_LOCALS 82
#define RETURN_VALUE    83
#define IMPORT_STAR 84
#define EXEC_STMT   85
#define YIELD_VALUE 86
#define POP_BLOCK   87
#define END_FINALLY 88
#define BUILD_CLASS 89

#define HAVE_ARGUMENT   90  /* Opcodes from here have an argument: */

#define STORE_NAME  90  /* Index in name list */
#define DELETE_NAME 91  /* "" */
#define UNPACK_SEQUENCE 92  /* Number of sequence items */
#define FOR_ITER    93

#define STORE_ATTR  95  /* Index in name list */
#define DELETE_ATTR 96  /* "" */
#define STORE_GLOBAL    97  /* "" */
#define DELETE_GLOBAL   98  /* "" */
#define DUP_TOPX    99  /* number of items to duplicate */
#define LOAD_CONST  100 /* Index in const list */
#define LOAD_NAME   101 /* Index in name list */
#define BUILD_TUPLE 102 /* Number of tuple items */
#define BUILD_LIST  103 /* Number of list items */
#define BUILD_MAP   104 /* Always zero for now */
#define LOAD_ATTR   105 /* Index in name list */
#define COMPARE_OP  106 /* Comparison operator */
#define IMPORT_NAME 107 /* Index in name list */
#define IMPORT_FROM 108 /* Index in name list */

#define JUMP_FORWARD    110 /* Number of bytes to skip */
#define JUMP_IF_FALSE   111 /* "" */
#define JUMP_IF_TRUE    112 /* "" */
#define JUMP_ABSOLUTE   113 /* Target byte offset from beginning of code */

#define LOAD_GLOBAL 116 /* Index in name list */

#define CONTINUE_LOOP   119 /* Start of loop (absolute) */
#define SETUP_LOOP  120 /* Target address (relative) */
#define SETUP_EXCEPT    121 /* "" */
#define SETUP_FINALLY   122 /* "" */

#define LOAD_FAST   124 /* Local variable number */
#define STORE_FAST  125 /* Local variable number */
#define DELETE_FAST 126 /* Local variable number */

#define RAISE_VARARGS   130 /* Number of raise arguments (1, 2 or 3) */
/* CALL_FUNCTION_XXX opcodes defined below depend on this definition */
#define CALL_FUNCTION   131 /* #args + (#kwargs<<8) */
#define MAKE_FUNCTION   132 /* #defaults */
#define BUILD_SLICE     133 /* Number of items */

#define MAKE_CLOSURE    134     /* #free vars */
#define LOAD_CLOSURE    135     /* Load free variable from closure */
#define LOAD_DEREF      136     /* Load and dereference from closure cell */ 
#define STORE_DEREF     137     /* Store into cell */ 

/* The next 3 opcodes must be contiguous and satisfy
   (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1  */
#define CALL_FUNCTION_VAR          140  /* #args + (#kwargs<<8) */
#define CALL_FUNCTION_KW           141  /* #args + (#kwargs<<8) */
#define CALL_FUNCTION_VAR_KW       142  /* #args + (#kwargs<<8) */

/* Support for opargs more than 16 bits long */
#define EXTENDED_ARG  143

4.解析pyc文件

好了到现在,关于PyCodeObject的pyc文件已经有了初步了解,我们可以用PycParser的工程对pyc进行解析,转化为可视的XML,在co_consts中,包含了另外的PyCodeObject,同时还包含了别的对象,实际上在co_consts中包含了Python源文件的中所定义的所有常量对象,即除了PyStringObject对象之外的所有对象。PyStringObject通常保存在co_names和co_varnames。

我们知道在生成pyc时,会将PyCodeObject对象中的字节码序列一起写入pyc文件中,而且这个pyc文件还记录了每一条字节码指令与Python源代码行号的对应关系,保存在co_Inotab中。

而 Python 库中 dis 的 dis 方法可以对 code对象 进行解析。接收 code对象,输出 字节码指令信息。

dis.dis 的输出:

  • 第一列,是 字节码指令 对应的 源代码 在 Python 程序中的行数
  • 第二列,是当前 字节码指令 在 co_code 中的偏移位置
  • 第三列,当前的字节码指令
  • 第四列,当前字节码指令的参数

test.py

import sys

a = 1

def b():
    print a
    a = 2
    print a
>>> source = open('/Users/chao/Desktop/test.py').read()
>>> co = compile(source, 'test.py', 'exec')
>>> import dis
>>> dis.dis(co)
  1           0 LOAD_CONST               0 (-1)
              3 LOAD_CONST               1 (None)
              6 IMPORT_NAME              0 (sys)
              9 STORE_NAME               0 (sys)

  3          12 LOAD_CONST               2 (1)
             15 STORE_NAME               1 (a)

  5          18 LOAD_CONST               3 (<code object b at 0x1005dc930, file "test.py", line 5>)
             21 MAKE_FUNCTION            0
             24 STORE_NAME               2 (b)
             27 LOAD_CONST               1 (None)
             30 RETURN_VALUE
>>> type(co)
<type 'code'>
>>> dir(co)
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
>>> print co.co_names
('sys', 'a', 'b')
>>> print co.co_name
<module>
>>> print co.co_filename
test.py

 

 

python 源码分析 基本篇 以后都在 github 更新,请参考Cpython Internals 版本 第一步克隆 Cpython 仓库到本地, 切换到我当前的版本, 我当前的版本号是3.8.0a0 git clone https://github.com/python/cpython.git git reset --hard ab54b9a130c88f708077c2ef6c4963b632c132b... 阅读详情

相关推荐

Python之美[从菜鸟到高手]--urlparse源码分析

urlparse是用来解析url格式的,url格式如下:protocol :// hostname[:port] / path / [;parameters][?query]#fragment,其中;parameters一般用来指定特殊参数,使用的较少,至少我没怎么碰到,举几个链接:http://en.wikipedia.org/wiki/Robotics;Notes,http://en.wiki

Skycrab 8577

初探Python字节码和dis模块

本文主要介绍 Python 字节码、Python 虚拟机内幕以及 dis 模块的简单应用。阅读本文预计 10 min. 初探Python字节码和dis模块1. 前言2. Python 字节码2.1 汇编与反汇编2.2 什么是 Python 字节码呢?2.3 为什么需要 Python 字节码?3. Python 虚拟机内幕4. dis 模块4.1 访问和理解 Python 字节码4.2 dis() 方法5. 更多的推荐6. 巨人的肩膀 1. 前言 了解 Python 字节码和 Python 虚拟机运行的知.

Jock2018的博客 5235

Python bisect模块的使用与源码分析

文章目录1. 模块简介2. 源码分析及使用2.1. 方法概述2.2. 使用2.3. 源码分析 本文基于Python3.7分析 1. 模块简介 bisect模块属于Python内置模块 内部核心算法是二分法 用于操作的列表必须是升序的(空列表也可以) 功能: 在保证原有顺序的情况下, 插入一个元素(或返回元素如果插入的下标值),不影响原有顺序 2. 源码分析及使用 2.1. 方法概述 bisect提供了六个方法: 查找: 返回元素按照顺序应该插入的位置, 但不会修改原列表 方法 解释

ww08153115的博客 634

(笔记)Python库 :dis

Python是一种解释型语言,在执行时会将Python源代码编译为一组虚拟机指令,并且Python解释器是针对相应的虚拟机实现的,这种中间格式被称为字节码( bytecode )。 Python文件名以 .py 结尾,但是还可能看到其他后缀名的文件,比如以 .pyc 结尾的文件,这些文件就是Python的字节码( bytecode )文件,在Python 3 中,这种文件可能不容易看到,因为字节码文件与 .py 文件不在同一个目录下,它们在一个叫做 __pycache__ 的子目录中,这也是P..

Hanlin的博客 1197

Python之美[从菜鸟到高手]--urllib源码分析

urllib提供了较好的封装,可以很方便的读取http,ftp,file等协议数据,本篇只关注http。urllib的底层还是使用httplib模块,相比于httplib,urllib接口更加好用,功能更加强大。支持http代理,可从环境变量中获取代理信息,支持http basic auth,可自动处理302等。但也有不足,如不支持gzip等压缩编码,不支持摘要认证,NTML认证等。

Skycrab 1万+

源码分析工具Joern的安装(新旧版本)

文章目录老版本安装新版本安装依赖库安装预先build好的二进制程序设置一下分配的内存大小测试一下安装的结果 老版本安装 官方链接:https://joern.readthedocs.io/en/latest/installation.html 老版本安装的话,可能会遇到的问题是neo4j的老版本比较难下载。一些博客也给出了解决方案:https://blog.csdn.net/water_likly/article/details/88415127 新版本安装 官方链接:https://joern.io/do

^_^ 4339

pythondis功能_python中dis的用法

dis库是python(默认的CPython)自带的一个库,可以用来分析字节码例子首先导入dis库>>> import dis然后在repl中,创建一个函数>>> def add(a, b = 0):... return a + b...>>>最后将add函数传给dis库的dis函数>>> dis.dis(add)2 ...

weixin_39774445的博客 1827

Python彩蛋源码分析(二)

简介???? 非常高兴大家能够订阅这个专栏,在这里我将会给大家分享一些Python相关源码的剖析 在接下来的这段日子里,我会一同带各位pythonista探索Python的奥秘

you are sherlocked by me! 3556

如何查看Python解释执行的底层细节

在Python中,dis模块提供了一个称为dis.dis()的函数,这是一个非常有用的工具,用于反汇编Python字节码。这可以帮助开发者理解Python代码是如何被解释和执行的,特别是在性能分析、调试或学习Python的底层工作原理时。

酌沧 1164

Python之禅(The Zen of Python)源码分析

简介???? 非常高兴大家能够订阅这个专栏,在这里我将会给大家分享一些Python相关源码的剖析 在接下来的这段日子里,我会一同带各位pythonista探索Python的奥秘 该从什么开始 思来想去,我觉得作为一个Python初学者还是Python的成熟的开发者,都应该从The Zen of Python开始 在这里非常感谢我们的龟叔(Guido van Rossum)于1989年圣诞节期间,创造出了Python这门语言 Python名字的由来 龟叔非常喜欢一部BBC电视剧(Monty Pyth

you are sherlocked by me! 1483

Telegram Bot Api使用教程

其中token为你的机器人token,method为telegram给定的方法,在获取群组chat_id那一步就使用了telegram的其中一个方法(getUpdates),其他方法后面会介绍。telegram发送消息的方式类似与钉钉机器人,都是向一个api发送http请求,而且对于同一个APItelegram支持GET和POST两种请求方式.请求的api格式如下。通常来说我们都需要让机器人在一个群组里工作,所以首先我们需要将机器人添加到我们指定的群组,在群组里发送随意消息并@这个机器人,比如...

豫迷糊的码上生活 1万+

Boost-源码分析笔记8-any

喜欢这篇文章吗?喜欢的话去看博主的置顶博客,即可依据分类找到此文章的原版得到更好的体验, 图片及代码显示的问题,笔者深感抱歉,想要更好的体验去原博文即可。 title: Boost 源码分析笔记8 - any mathjax: true date: 2020-03-17 16:55:58 categories: [c++笔记,Boost源码分析笔记] tags: [c++笔记,Boost源码分析...

fightinggg的博客 324

电蚊拍为什么能秒杀蚊子?深入解析两种四倍压整流电路设计差异

本文深入解析电蚊拍秒杀蚊子的核心原理——四倍压整流电路设计,对比对称式与级联式两种方案的性能差异。通过详细电路分析、实测数据对比和选型建议,揭示高压电路设计的关键技术要点,为电子爱好者和工程师提供实用参考。

rust6ferris的博客 751

python 列表对象 底层实现 源码分析 PyListObject(list)

PyListObject 本文参考的是3.8.0a0 版本的代码,详见cpython 源码分析 基本篇 以后都在 github 更新,请参考图解 python list 用过python 的童鞋都知道 python 内建了好几种数据结构,其中一种就是 list,你可以通过如下的方法定义一个 list a = [] b = [] c = list((1, 2, 3)) d = c...

zpoint's blog 1378

北斗B1频点信号捕获实战:如何应对NH码跳变带来的挑战?

本文深入探讨了北斗B1频点信号捕获中NH码跳变带来的核心挑战。针对NH码以1kHz速率调制导致的相干积分中断和相关峰畸变问题,文章提出并详细解析了一种基于伪码与多普勒频率分离技术的优化捕获方案。该方案通过差分处理消除NH跳变影响,并利用匹配滤波器与FFT分别进行码相位和多普勒频率的快速估计,有效提升了弱信号环境下的捕获灵敏度和稳定性,为北斗接收机设计提供了实用的工程参考。

joy55的博客 535

STM32实现webserver显示数据及配置参数

其实提到的将fsdata.c重命名为fsdata_custom.c,可以不重命令,将/LWIP/Target/lwipopts.h中HTTPD_USE_CUSTOM_FSDATA 定义为0,这样HTTPD_FSDATA_FILE将使用fsdata.c,避免每次生成fsdata.c需要重命令的麻烦。2、登录成功后,板卡根据板卡配置类型,返回对应的数据页面,该页面可实现数据校准、清零,以及进行到板卡参数设置页面。目前还未实现post功能以及http身份验证功能。3、板卡参数设置页面。

2694

Python IDLE源码分析-序

Python IDLE源码分析-序:IDLE是如何工作的?

qq_57140570的博客 1012

MacOS M芯片部署ComfyUI:从环境排雷到插件生态一站式指南

本文为MacOS M系列芯片用户提供了一份详尽的ComfyUI部署指南。文章深入剖析了因架构差异导致的常见安装报错根源,并给出了基于MPS后端的正确PyTorch安装命令。从创建纯净Python虚拟环境、分步安装依赖,到验证GPU加速,手把手指导完成部署。同时,还推荐了包括管理器、汉化在内的必备插件,以完善使用生态,帮助用户一站式解决从环境搭建到效率提升的所有问题。

weixin_29261711的博客 994

Qwen3-0.6B-FP8应用开发:Python源码分析工具

本文介绍了如何在星图GPU平台自动化部署⚡ Qwen3-0.6B-FP8极速对话工具,用于开发Python源码分析应用。该工具能自动解析代码逻辑、提供优化建议并生成文档,显著提升代码维护与理解效率,适用于中大型项目的智能代码审查和文档自动化生成场景。

weixin_35307279的博客 20

GNSS - PPP软件 - GAMP 在VS2019/2022下完成调试、跑通程序(超详细!)

WIN32;_DEBUG;_CONSOLE;O_WARNINGS;ENAGLO;ENACMP;ENAGAL;ENAQZS;NFREQ=3。

qq_43381998的博客 8251

Unreal5从入门到精通之如何在VR中使用3DUI

前面我们讲过《Unreal5从入门到精通之UMG的使用》一般制作游戏时,UI都是添加到屏幕视窗上面的,但是在制作VR时,我们往往需要制作一个3D的UI,放置在场景中,然后使用手柄的射线来和UI进行交互。今天我们就来讲解下,如何在VR中创作和交互3DUI首次操作会感觉好复杂,多多练习,当你熟悉了UE蓝图的操作后会发现,这只是一个常规的蓝图操作而已。祝大家在虚幻的学习过程中非常顺利。希望这篇博客对你有所帮助。

TxNet 1985

Condition源码分析

Condition源码分析 文章目录Condition源码分析前言ConditionCondition源码分析实例化初探notify和waitnotifywaitwait_for 前言 除了之前在Python中的线程锁中提到的Lock和RLock,Python中的同步机制还有Conditions,我称其为条件锁。以下是我对Condition类的使用以及相关源码分析。 Condition 条件同...

有关心情 544

DeepLabv3+改进68:全网首发-添加DBlock模块 |高效且鲁棒的多任务低光图像修复神经网络

本文提出了一种高效鲁棒的多任务低光图像修复神经网络DarkIR,针对夜间或昏暗条件下图像存在的噪点、光线不足和模糊问题。不同于现有方法分别处理去模糊和低光增强任务,该模型采用新的注意力机制增强CNN感受野,在降低计算成本的同时,在LOL-Blur、LOLv2和Real-LOLBlur数据集上取得最优结果,并能良好泛化到真实夜间图像。

AIcurator的博客 325

【Java8新特性系列】 List接口新特性示例源码分析

在Java 8之前,接口只能定义抽象方法,即不带实现的方法。这限制了接口的功能,并导致使用接口的类需要重复实现相同的代码。为了解决这个问题,Java 8引入了默认方法(default method)的概念,允许在接口中定义带有默认实现的方法。默认方法通过。当一个类实现了一个接口,并且没有提供默认方法的实现时,它将继承接口中的默认方法实现。如果一个类实现了多个接口,并且这些接口都包含具有相同签名的默认方法,那么实现类必须覆盖这个默认方法,以明确指定使用哪个接口的实现。

wang2leee的博客 172

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【Python】实现URL-sql注入检测+源码分析

上篇博客写到了对原始URL爬行页面提取有效URL这篇继续深入,当提取到URL后开始检测是否存在注入漏洞  SQL注入检测思路:                 爬行网址,提取带有参数的url  如 http://www.target.com/show.asp?id=666 这样的url地址                 然后通过5重验证 :

浪子燕青的博客 9311

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

python apscheduler_源码分析python apscheduler的实现

今天的话题是,源码分析python apscheduler计划任务的实现. 不知道为什么总是跟计划任务较真,自己一些实现了一个分布式的定时任务系统,也在博客中做过分享,但还是很喜欢看看别人是怎么写的,有什么可以借鉴的。新版的apscheduler 3.1.x有些太杂乱了,在3.x版本里面加了各种的运行模式,比如gevent,多进程啥的. 如果只是想看他的实现原理那我们就直接看他的经典版本2.1版...

weixin_39686634的博客 232

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

上一篇: flask学习(一)
下一篇: mysql-Alter
smartab
博客等级 码龄9年 34粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值